Android 音乐播放器的开发教程(七)运用Broadcast实现service与activity的通信 ----- 小达
2014-12-29 09:25
573 查看
运用Broadcast实现service与activity的通信
做到了这一步,现在的播放器应该可以显示歌曲列表,能够点击并播放音乐了哈,但是上面的按钮一个都不能点啊有没有,一旦放起来停都停不下来,不要着急,这一篇博客将介绍怎么将activity上的按钮都派上用场. 前面介绍过了,播放歌曲是在一个service中进行的,而按钮在activity和fragment上,怎么才能让它们联系起来呢?这就要用到安卓的另外一个四大组件之一----Broadcast,通常翻译为广播(感觉又是怪怪的样子),Broadcast是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver是对发送出来的 Broadcast进行过滤接受并响应的一类组件。这篇将介绍如何实现service和activity的通信. 发送广播的方式很简单,只需要新建一个Intent,里面存放一些需要传出去的信息即可,例如Intent intent_to_activity = new Intent(<span style="color:#ff9966;">"com.dada.communication.RECEIVER"</span>); //这个intent中的字符串可以自定义,只需要在广播***上与这个字符串一样即可,下面会提到的.
intent_to_activity.putExtra("title", intent.getStringExtra("title")); intent_to_activity.putExtra("artist", intent.getStringExtra("artist")); intent_to_activity.putExtra("album", intent.getStringExtra("album")); intent_to_activity.putExtra("album_id", intent.getLongExtra("album_id", 0));这样就把信息存放在了intent_to_activity中了,之后再用一句话,sendBroadcast(intent_to_activity)将这个包含信息的intent发送出去,发送广播的工作就已经做完啦,发出广播之后,还需要接收这个消息,这里需要实现的是activity和service的通信,故一边发,另外一边接收,上面的代码是写在service中的,故***应写在activity中. 定义广播的***,有三个步骤, 第一步: 定义一个自定义Receiver类,需要继承Broadcast类,其中写入收到广播之后,需要执行的代码,例如:
private class MsgReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { music_info_textView = (TextView)findViewById(R.id.music_info_textView); singer_info_textView = (TextView)findViewById(R.id.singer_info_textView); music_info_textView.setText(intent.getStringExtra("title")); singer_info_textView.setText(intent.getStringExtra("artist")); } }第二步: 实例化这个类,并创建一个IntentFilter,这个相当于一个广播的过滤器,对其进行操作,可以过滤出自己想要监听的广播.
IntentFilter intentMsgFilter = new IntentFilter();第三步: 对IntentFilter操作,并将其与第一步定义的***绑定在一起.
intentMsgFilter.addAction(<span style="color:#ff6666;">"com.example.communication.RECEIVER"</span>); //注册歌曲信息的广播***,需要与上面发送广播的intent字符串一致 registerReceiver(msgReceiver,intentMsgFilter);到这里,广播的收发就能进行了,是不是比较容易.下面就给出MainActivity.java和PlayerService.java的代码,红色部分为基于上一篇的改动,里面主要就是实现了播放与暂停键的相应,歌曲名和艺术家名的显示,还有进度条的更新.MainActivity.java
package com.example.dada.myapplication; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.ImageButton; import android.widget.SeekBar; import android.widget.TextView; import java.util.List; public class MainActivity extends ActionBarActivity implements MainFragment.OnFragmentInteractionListener, MyMusicFragment.OnFragmentInteractionListener{ private boolean isPause; //记录当前播放器的状态 private FragmentManager fragmentManager; private FragmentTransaction fragmentTransaction; private MyMusicFragment myMusicFragment; private MainFragment mainFragment; private FindSongs finder; //查找歌曲的类 public static List<Mp3Info> mp3Infos; //歌曲列表 public static int music_position; //音乐的位置 <span style="color:#ff0000;"> private int current_position; //当前进度条的位置</span> <span style="color:#ff0000;">private ImageButton play_button; //播放按钮控件 private TextView music_info_textView; //显示歌曲信息的textview private TextView singer_info_textView; //显示歌手信息的textview private SeekBar seek_bar; //进度条控件 </span> <span style="color:#ff0000;"> private MsgReceiver msgReceiver; //service发过来的广播*** private BarReceiver barReceiver; //进度条的*** private Intent intent_to_service; //向service发送广播的intent</span> /* 这个方法是activity和fragment通信的一种方法 在MainFragment中调用这个方法,可以在activity中做出相应的反应 */ public void onMainFragmentInteraction(int msg){ /* 对其中的参数msg做出判断,如果为CHANGE_TO_MY_MUSIC_FRAGMENT 则执行跳转 */ if(msg == AppConstant.PlayerMsg.CHANGE_TO_MY_MUSIC_FRAGMENT){ /* 在这里并没有直接切换Fragment 而是调用了activity实现MyMusicFragment的那个接口 对后面的开发能带来一点便利之处 */ onMyMusicFragmentInteraction(AppConstant.PlayerMsg.CHANGE_TO_MY_MUSIC_FRAGMENT); } } public void onMyMusicFragmentInteraction(int msg){ myMusicFragment = new MyMusicFragment(); //创建了MyMusicFragment的实例 FragmentManager fragmentManager = getFragmentManager(); //得到FragmentManager FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); //得到fragmentTransaction if(msg == AppConstant.PlayerMsg.CHANGE_TO_MY_MUSIC_FRAGMENT){ fragmentTransaction.replace(R.id.fragment_layout, myMusicFragment); fragmentTransaction.addToBackStack(null); //这句话是将被替换的MainFragment加入到一个专门存放fragment的栈中,在回退的时候显示上一个Fragment fragmentTransaction.commit(); } if(msg == AppConstant.PlayerMsg.BACK_TO_MAIN_FRAGMENT){ fragmentTransaction.replace(R.id.fragment_layout, mainFragment); fragmentTransaction.addToBackStack(null); fragmentTransaction.commit(); } } public void onMyMusicFragmentInteraction(int msg,int position){ if(msg == AppConstant.PlayerMsg.LIST_CLICK){ if (mp3Infos != null) { isPause = false; initService(position); } } }
<span style="color:#ff0000;">/*</span>
<span style="color:#ff0000;">这个方法是重写了activity里自带的方法onStart()</span>
<span style="color:#ff0000;">里面要带上super.onStart();不然会报错的</span>
<span style="color:#ff0000;">*/</span> <span style="color:#ff0000;"> @Override protected void onStart(){ super.onStart(); IntentFilter intentMsgFilter = new IntentFilter(); IntentFilter intentBarFilter = new IntentFilter(); intentMsgFilter.addAction("com.example.communication.RECEIVER"); //注册歌曲信息的广播*** registerReceiver(msgReceiver,intentMsgFilter); intentBarFilter.addAction("com.example.communication.BAR"); //注册进度条的广播*** registerReceiver(barReceiver,intentBarFilter); }</span> @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); music_position = 0; <span style="color:#ff0000;"> current_position = 0;</span> finder = new FindSongs(); <span style="color:#ff0000;"> msgReceiver = new MsgReceiver(); barReceiver = new BarReceiver();</span> mp3Infos = finder.getMp3Infos(getContentResolver()); <span style="color:#ff0000;"> intent_to_service = new Intent("com.example.communication.PLAY"); seek_bar = (SeekBar)findViewById(R.id.process_bar); play_button = (ImageButton)findViewById(R.id.play_button); play_button.setImageResource(R.drawable.play_photo);</span> <span style="color:#ff0000;"> play_button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(isPause){ isPause = false; play_button.setImageResource(R.drawable.pause_photo); } else{ isPause = true; play_button.setImageResource(R.drawable.play_photo); } </span>
<span style="color:#ff0000;">/*</span>
<span style="color:#ff0000;">将音乐播放到了的当前位置和当前的状态</span>
<span style="color:#ff0000;">以广播的形式发送给service</span>
<span style="color:#ff0000;">来让service可以接着刚才暂停的位置开始播放</span>
<span style="color:#ff0000;">而不是重新播放</span>
<span style="color:#ff0000;">*/</span>
<span style="color:#ff0000;"> intent_to_service.putExtra("position",current_position); intent_to_service.putExtra("isPause",isPause); sendBroadcast(intent_to_service); } });</span> mainFragment = new MainFragment(); //创建了刚才定义的MainFragment实例 fragmentManager = getFragmentManager(); //得到FragmentManager fragmentTransaction = fragmentManager.beginTransaction(); //得到fragmentTransaction,用于管理fragment的切换 fragmentTransaction.replace(R.id.fragment_layout, mainFragment).commit(); //将MainActivity里的布局模块fragment_layout替换为mainFragment } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } private void initService(int position) { music_position = position; Mp3Info mp3Info = mp3Infos.get(position); <span style="color:#ff0000;"> seek_bar.setMax((int)mp3Info.getDuration()); //获取当前播放歌曲的长度,设置进度条的最大值</span> /* 这里新建了一个Intent 里面存放各种即将传给Service的数据 要启动自定义PlayerService类 还需要在AndroidManifest中加入如下代码 <service android:name="com.example.dada.myapplication.PlayerService" android:exported="false" > </service> */ Intent intent = new Intent("com.example.communication.MSG_ACTION"); play_button.setImageResource(R.drawable.pause_photo); intent.putExtra("url", mp3Info.getUrl()); intent.putExtra("title", mp3Info.getTitle()); intent.putExtra("artist", mp3Info.getArtist()); intent.putExtra("album", mp3Info.getAlbum()); intent.putExtra("album_id", mp3Info.getAlbum_id()); intent.putExtra("MSG", AppConstant.PlayerMsg.PLAY_MSG); intent.setClass(MainActivity.this, PlayerService.class); startService(intent); } <span style="color:#ff0000;"> private class MsgReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { music_info_textView = (TextView)findViewById(R.id.music_info_textView); singer_info_textView = (TextView)findViewById(R.id.singer_info_textView); </span>
<span style="color:#ff0000;">/*</span>
<span style="color:#ff0000;">从接收到的广播的intent中取出发送过来的信息</span>
<span style="color:#ff0000;">这里是取出了歌曲名和艺术家名</span>
<span style="color:#ff0000;">*/</span>
<span style="color:#ff0000;"> music_info_textView.setText(intent.getStringExtra("title")); singer_info_textView.setText(intent.getStringExtra("artist")); } } private class BarReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) {</span>
<span style="color:#ff0000;">/*</span>
<span style="color:#ff0000;">取出后,更新进度条当前的位置</span>
<span style="color:#ff0000;">*/ current_position = intent.getIntExtra("position",0); seek_bar.setProgress(current_position); } } }</span>PlayerService.java
package com.example.dada.myapplication; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.MediaPlayer; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.view.animation.AnimationUtils; import android.widget.RemoteViews; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class PlayerService extends Service implements AppConstant { private int current_position; private String musicPath; private String music_artist; private String music_title; private String notification_msg; private boolean isPause = true; private boolean isChangToNext; <span style="color:#ff0000;"> private PlayReceiver playReceiver; //自定义的广播***</span> public static MediaPlayer mediaPlayer = new MediaPlayer(); <span style="color:#ff0000;"> private Intent intent_to_activity = new Intent("com.example.communication.RECEIVER"); //发送广播的intent private Intent intent_to_progressBar = new Intent("com.example.communication.BAR");</span>
<span style="color:#ff0000;"> </span><span style="color: rgb(255, 0, 0); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">/*这里运用到了Handler对各种消息的处理,主要是用它来更新UI</span>
<span style="font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;color:#ff0000;"> 在下面代码的自定义广播***类中,收到消息后,会给这个myHandler发送消息</span>
<span style="font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;color:#ff0000;">再由这个myHandler做统一的处理</span>
<span style="color: rgb(255, 0, 0); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">*/</span>
<span style="color:#ff0000;"> private Handler myHandler = new Handler() { </span>
<span style="color:#ff0000;"> public void handleMessage(Message msg) { if (msg.what == PlayerMsg.PLAY_MSG) { current_position = mediaPlayer.getCurrentPosition(); intent_to_progressBar.putExtra("position", current_position); sendBroadcast(intent_to_progressBar); myHandler.sendEmptyMessageDelayed(PlayerMsg.PLAY_MSG, 1000); } if (msg.what == PlayerMsg.PAUSE) { stopMusic(); } } };</span> @Override public IBinder onBind(Intent intent) { return null; } public int onStartCommand(Intent intent, int flags, int startId) { notification_msg = null;
<span style="color:#ff0000;">/*</span>
<span style="color:#ff0000;">这里就是前面讲到的接收广播的三部曲</span>
<span style="color:#ff0000;">*/</span> <span style="color:#ff0000;">playReceiver = new PlayReceiver(); IntentFilter intentPlayFilter = new IntentFilter(); intentPlayFilter.addAction("com.example.communication.PLAY"); registerReceiver(playReceiver, intentPlayFilter);</span> try { int msg = intent.getIntExtra("MSG", 0); musicPath = intent.getStringExtra("url"); <span style="color:#ff0000;">SendBroadcastToActivity(intent);</span> if (msg == AppConstant.PlayerMsg.PLAY_MSG) {
<span style="color:#ff0000;">/*</span>
<span style="color:#ff0000;">向myHandler发送消息,由myHandler做出处理</span>
<span style="color:#ff0000;">*/</span> <span style="color:#ff0000;"> myHandler.sendEmptyMessage(PlayerMsg.PLAY_MSG); </span> playMusic(0); } } catch (Exception e) { e.printStackTrace(); } return 0; } private void playMusic(int position) { try { mediaPlayer.reset(); mediaPlayer.setDataSource(musicPath); mediaPlayer.prepare(); mediaPlayer.setOnPreparedListener(new MyPreparedListener(position));
} catch (IOException e) { e.printStackTrace(); } } private class MyPreparedListener implements MediaPlayer.OnPreparedListener { private int position; public MyPreparedListener(int position) { this.position = position; } public void onPrepared(MediaPlayer mp) { if (position > 0) mediaPlayer.seekTo(position); mediaPlayer.start(); } } private void stopMusic() { if (mediaPlayer != null) { mediaPlayer.pause(); } } public void onDestory() { if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); } } <span style="color:#ff0000;"> private void SendBroadcastToActivity(Intent intent) { //向activity发送广播的函数 music_title = intent.getStringExtra("title"); music_artist = intent.getStringExtra("artist"); intent_to_activity.putExtra("title", intent.getStringExtra("title")); intent_to_activity.putExtra("artist", intent.getStringExtra("artist")); intent_to_activity.putExtra("album", intent.getStringExtra("album")); intent_to_activity.putExtra("album_id", intent.getLongExtra("album_id", 0)); sendBroadcast(intent_to_activity); } private class PlayReceiver extends BroadcastReceiver { //播放与暂停广播*** public PlayReceiver() { super(); } @Override public void onReceive(Context context, Intent intent) { isPause = intent.getBooleanExtra("isPause", true); isChangToNext = intent.getBooleanExtra("isChangeToNext", false); if (isPause) { myHandler.sendEmptyMessage(PlayerMsg.PAUSE); } else { current_position = intent.getIntExtra("position", 0); playMusic(current_position); myHandler.sendEmptyMessage(PlayerMsg.PLAY_MSG); } } }</span>}上面好长好长的代码,实现的就是能暂停和播放,进度条能显示播放进度,activity能显示歌曲信息,其中包含了两个Broadcast的收发,一个handler的应用.广播在android开发中用的还是比较多的,感觉也是比较好用的哈. 上面还有什么不明白的地方,可以给我留言,也可以直接Q我,2319821734,小达有什么做错了的,做的不好的,还请各位多多指出,在下一篇中将实现切歌的功能,还有进度条的拖动播放.88~~~~~
相关文章推荐
- Android 音乐播放器的开发教程(六)service的运用及音乐列表点击播放 ----- 小达
- Android 音乐播放器的开发教程(四)Activity和Fragment的通信以及Fragment的切换 ----- 小达
- Android 音乐播放器的开发教程(十一)SQLite的使用及最近播放的实现 ----- 小达
- Android 音乐播放器的开发教程(十二)SQLite的使用及我的最爱歌曲的实现 ----- 小达
- Android之Activity ContentProvider Service Broadcast,线程间通信,AIDL(三)
- Android 音乐播放器的开发教程(一) ----- 小达
- Android Service与Activity之间通信的几种方式(1)---通过broadcast(广播)的形式
- Android 音乐播放器的开发教程(三) 小卷毛播放器的主界面开发 ---- 小达
- Android零基础开发专题五:Activity、BroadcastReceiver、Service、Content Provider
- Android开发笔记(2) Android Bundle类实现Activity之间通信
- android开发之使用Messenger实现service与activity交互
- android开发之使用Messenger实现service与activity交互
- Android 音乐播放器的开发教程(十)通知栏Notification的使用 ----- 小达
- Android中aidl实现Activity与service进行通信和回调
- Android开发之Service的写法以及与Activity的通信
- Android 音乐播放器的开发教程(五)本地音乐的获取及显示 ----- 小达
- Android之Activity ContentProvider Service Broadcast,线程间通信,AIDL(一)
- Android应用开发教程:两个运行的Activity之间的通信
- Android 初步学习BroadCast与Service实现简单的音乐播放器
- android开发之使用Messenger实现service与activity交互