Android 音乐播放器的开发教程:运用Broadcast实现service与activity的通信

运用Broadcast实现service与activity的通信


       做到了这一步,现在的播放器应该可以显示歌曲列表,能够点击并播放音乐了哈,但是上面的按钮一个都不能点啊有没有,一旦放起来停都停不下来,不要着急,这一篇博客将介绍怎么将activity上的按钮都派上用场.
        
        前面介绍过了,播放歌曲是在一个service中进行的,而按钮在activity和fragment上,怎么才能让它们联系起来呢?这就要用到安卓的另外一个四大组件之一----Broadcast,通常翻译为广播(感觉又是怪怪的样子),Broadcast是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver是对发送出来的 Broadcast进行过滤接受并响应的一类组件。这篇将介绍如何实现service和activity的通信.

        发送广播的方式很简单,只需要新建一个Intent,里面存放一些需要传出去的信息即可,例如

[java]  view plain  copy
 print ?
  1. Intent intent_to_activity = new Intent("color:#ff9966;">"com.dada.communication.RECEIVER");    //这个intent中的字符串可以自定义,只需要在广播接收器上与这个字符串一样即可,下面会提到的.  
[java]  view plain  copy
 print ?
  1. intent_to_activity.putExtra("title", intent.getStringExtra("title"));  
  2.         intent_to_activity.putExtra("artist", intent.getStringExtra("artist"));  
  3.         intent_to_activity.putExtra("album", intent.getStringExtra("album"));  
  4.         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类,其中写入收到广播之后,需要执行的代码,例如:
[java]  view plain  copy
 print ?
  1. private class MsgReceiver extends BroadcastReceiver {  
  2.         @Override  
  3.         public void onReceive(Context context, Intent intent) {  
  4.             music_info_textView = (TextView)findViewById(R.id.music_info_textView);  
  5.             singer_info_textView = (TextView)findViewById(R.id.singer_info_textView);  
  6.   
  7.             music_info_textView.setText(intent.getStringExtra("title"));  
  8.             singer_info_textView.setText(intent.getStringExtra("artist"));  
  9.   
  10.         }  
  11.     }  
         
        第二步:   实例化这个类,并创建一个IntentFilter,这个相当于一个广播的过滤器,对其进行操作,可以过滤出自己想要监听的广播.
[java]  view plain  copy
 print ?
  1. IntentFilter intentMsgFilter = new IntentFilter();  

          第三步:   对IntentFilter操作,并将其与第一步定义的接收器绑定在一起.
[java]  view plain  copy
 print ?
  1. intentMsgFilter.addAction("color:#ff6666;">"com.example.communication.RECEIVER");        //注册歌曲信息的广播接收器,需要与上面发送广播的intent字符串一致  
  2.         registerReceiver(msgReceiver,intentMsgFilter);  

        到这里,广播的收发就能进行了,是不是比较容易.下面就给出MainActivity.java和PlayerService.java的代码,红色部分为基于上一篇的改动,里面主要就是实现了播放与暂停键的相应,歌曲名和艺术家名的显示,还有进度条的更新.

MainActivity.java
[java]  view plain  copy
 print ?
  1. package com.example.dada.myapplication;  
  2.   
  3. import android.app.FragmentManager;  
  4. import android.app.FragmentTransaction;  
  5. import android.content.BroadcastReceiver;  
  6. import android.content.Context;  
  7. import android.content.Intent;  
  8. import android.content.IntentFilter;  
  9. import android.net.Uri;  
  10. import android.support.v7.app.ActionBarActivity;  
  11. import android.os.Bundle;  
  12. import android.view.Menu;  
  13. import android.view.MenuItem;  
  14. import android.view.View;  
  15. import android.widget.ImageButton;  
  16. import android.widget.SeekBar;  
  17. import android.widget.TextView;  
  18.   
  19. import java.util.List;  
  20.   
  21.   
  22. public class MainActivity extends ActionBarActivity  
  23.         implements MainFragment.OnFragmentInteractionListener,  
  24.                    MyMusicFragment.OnFragmentInteractionListener{  
  25.   
  26.   
  27.     private boolean isPause;                                               //记录当前播放器的状态  
  28.     private FragmentManager fragmentManager;  
  29.     private FragmentTransaction fragmentTransaction;  
  30.     private MyMusicFragment myMusicFragment;  
  31.     private MainFragment mainFragment;  
  32.     private FindSongs finder;                                              //查找歌曲的类  
  33.     public static List mp3Infos;                                  //歌曲列表  
  34.     public static int music_position;                                      //音乐的位置  
  35. "color:#ff0000;">    private int current_position;                                          //当前进度条的位置  
  36.   
  37.     "color:#ff0000;">private ImageButton play_button;                                       //播放按钮控件  
  38.     private TextView music_info_textView;                                  //显示歌曲信息的textview  
  39.     private TextView singer_info_textView;                                 //显示歌手信息的textview  
  40.     private SeekBar seek_bar;                                              //进度条控件  
  41.   
  42.   "color:#ff0000;">  private MsgReceiver msgReceiver;                                       //service发过来的广播接收器  
  43.     private BarReceiver barReceiver;                                       //进度条的接收器  
  44.   
  45.     private Intent intent_to_service;                                      //向service发送广播的intent  
  46.   
  47.   
  48.     /* 
  49.     这个方法是activity和fragment通信的一种方法 
  50.     在MainFragment中调用这个方法,可以在activity中做出相应的反应 
  51.      */  
  52.     public void onMainFragmentInteraction(int msg){  
  53.   
  54.         /* 
  55.         对其中的参数msg做出判断,如果为CHANGE_TO_MY_MUSIC_FRAGMENT 
  56.         则执行跳转 
  57.          */  
  58.         if(msg == AppConstant.PlayerMsg.CHANGE_TO_MY_MUSIC_FRAGMENT){  
  59.   
  60.             /* 
  61.             在这里并没有直接切换Fragment 
  62.             而是调用了activity实现MyMusicFragment的那个接口 
  63.             对后面的开发能带来一点便利之处 
  64.              */  
  65.             onMyMusicFragmentInteraction(AppConstant.PlayerMsg.CHANGE_TO_MY_MUSIC_FRAGMENT);  
  66.         }  
  67.     }  
  68.   
  69.     public void onMyMusicFragmentInteraction(int msg){  
  70.   
  71.         myMusicFragment = new MyMusicFragment();       //创建了MyMusicFragment的实例  
  72.         FragmentManager fragmentManager = getFragmentManager();   //得到FragmentManager  
  73.         FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); //得到fragmentTransaction  
  74.   
  75.   
  76.         if(msg == AppConstant.PlayerMsg.CHANGE_TO_MY_MUSIC_FRAGMENT){  
  77.   
  78.   
  79.   
  80.             fragmentTransaction.replace(R.id.fragment_layout, myMusicFragment);  
  81.             fragmentTransaction.addToBackStack(null);        //这句话是将被替换的MainFragment加入到一个专门存放fragment的栈中,在回退的时候显示上一个Fragment  
  82.             fragmentTransaction.commit();  
  83.   
  84.         }  
  85.   
  86.         if(msg == AppConstant.PlayerMsg.BACK_TO_MAIN_FRAGMENT){  
  87.   
  88.             fragmentTransaction.replace(R.id.fragment_layout, mainFragment);  
  89.             fragmentTransaction.addToBackStack(null);  
  90.             fragmentTransaction.commit();  
  91.         }  
  92.     }  
  93.   
  94.     public void onMyMusicFragmentInteraction(int msg,int position){  
  95.         if(msg == AppConstant.PlayerMsg.LIST_CLICK){  
  96.             if (mp3Infos != null) {  
  97.                 isPause = false;  
  98.                 initService(position);  
  99.             }  
  100.         }  
  101.     }  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">/*  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">这个方法是重写了activity里自带的方法onStart()  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">里面要带上super.onStart();不然会报错的  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">*/  
  2. "color:#ff0000;">    @Override  
  3.     protected void onStart(){  
  4.   
  5.         super.onStart();  
  6.         IntentFilter intentMsgFilter = new IntentFilter();  
  7.         IntentFilter intentBarFilter = new IntentFilter();  
  8.   
  9.   
  10.         intentMsgFilter.addAction("com.example.communication.RECEIVER");        //注册歌曲信息的广播接收器  
  11.         registerReceiver(msgReceiver,intentMsgFilter);  
  12.   
  13.         intentBarFilter.addAction("com.example.communication.BAR");             //注册进度条的广播接收器  
  14.         registerReceiver(barReceiver,intentBarFilter);  
  15.     }  
  16.   
  17.   
  18.     @Override  
  19.     protected void onCreate(Bundle savedInstanceState) {  
  20.         super.onCreate(savedInstanceState);  
  21.         setContentView(R.layout.activity_main);  
  22.   
  23.         music_position = 0;  
  24. "color:#ff0000;">        current_position = 0;  
  25.         finder = new FindSongs();  
  26.   
  27. "color:#ff0000;">        msgReceiver = new MsgReceiver();  
  28.         barReceiver = new BarReceiver();  
  29.   
  30.         mp3Infos = finder.getMp3Infos(getContentResolver());  
  31.   
  32. "color:#ff0000;">        intent_to_service = new Intent("com.example.communication.PLAY");  
  33.   
  34.         seek_bar = (SeekBar)findViewById(R.id.process_bar);  
  35.         play_button = (ImageButton)findViewById(R.id.play_button);  
  36.         play_button.setImageResource(R.drawable.play_photo);  
  37. "color:#ff0000;">        play_button.setOnClickListener(new View.OnClickListener() {  
  38.             @Override  
  39.             public void onClick(View v) {  
  40.                 if(isPause){  
  41.                     isPause = false;  
  42.                     play_button.setImageResource(R.drawable.pause_photo);  
  43.                 }  
  44.                 else{  
  45.                     isPause = true;  
  46.                     play_button.setImageResource(R.drawable.play_photo);  
  47.                 }   
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">/*  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">将音乐播放到了的当前位置和当前的状态  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">以广播的形式发送给service  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">来让service可以接着刚才暂停的位置开始播放  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">而不是重新播放  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">*/  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">                intent_to_service.putExtra("position",current_position);  
  2.                 intent_to_service.putExtra("isPause",isPause);  
  3.                 sendBroadcast(intent_to_service);  
  4.             }  
  5.         });  
  6.   
  7.         mainFragment = new MainFragment();           //创建了刚才定义的MainFragment实例  
  8.         fragmentManager = getFragmentManager();      //得到FragmentManager  
  9.         fragmentTransaction = fragmentManager.beginTransaction();   //得到fragmentTransaction,用于管理fragment的切换  
  10.         fragmentTransaction.replace(R.id.fragment_layout, mainFragment).commit();  //将MainActivity里的布局模块fragment_layout替换为mainFragment  
  11.     }  
  12.   
  13.   
  14.     @Override  
  15.     public boolean onCreateOptionsMenu(Menu menu) {  
  16.         // Inflate the menu; this adds items to the action bar if it is present.  
  17.         getMenuInflater().inflate(R.menu.menu_main, menu);  
  18.         return true;  
  19.     }  
  20.   
  21.     @Override  
  22.     public boolean onOptionsItemSelected(MenuItem item) {  
  23.         // Handle action bar item clicks here. The action bar will  
  24.         // automatically handle clicks on the Home/Up button, so long  
  25.         // as you specify a parent activity in AndroidManifest.xml.  
  26.         int id = item.getItemId();  
  27.   
  28.         //noinspection SimplifiableIfStatement  
  29.         if (id == R.id.action_settings) {  
  30.             return true;  
  31.         }  
  32.   
  33.         return super.onOptionsItemSelected(item);  
  34.     }  
  35.   
  36.     private void initService(int position) {  
  37.         music_position = position;  
  38.         Mp3Info mp3Info = mp3Infos.get(position);  
  39.   
  40. "color:#ff0000;">        seek_bar.setMax((int)mp3Info.getDuration());          //获取当前播放歌曲的长度,设置进度条的最大值  
  41.         /* 
  42.         这里新建了一个Intent 
  43.         里面存放各种即将传给Service的数据 
  44.         要启动自定义PlayerService类 
  45.         还需要在AndroidManifest中加入如下代码 
  46.  
  47.          
  48.             android:name="com.example.dada.myapplication.PlayerService" 
  49.             android:exported="false" 
  50.             > 
  51.          
  52.  
  53.          */  
  54.         Intent intent = new Intent("com.example.communication.MSG_ACTION");  
  55.         play_button.setImageResource(R.drawable.pause_photo);  
  56.         intent.putExtra("url", mp3Info.getUrl());  
  57.         intent.putExtra("title", mp3Info.getTitle());  
  58.         intent.putExtra("artist", mp3Info.getArtist());  
  59.         intent.putExtra("album", mp3Info.getAlbum());  
  60.         intent.putExtra("album_id", mp3Info.getAlbum_id());  
  61.         intent.putExtra("MSG", AppConstant.PlayerMsg.PLAY_MSG);  
  62.         intent.setClass(MainActivity.this, PlayerService.class);  
  63.         startService(intent);  
  64.     }  
  65.   
  66. "color:#ff0000;">    private class MsgReceiver extends BroadcastReceiver {  
  67.         @Override  
  68.         public void onReceive(Context context, Intent intent) {  
  69.             music_info_textView = (TextView)findViewById(R.id.music_info_textView);  
  70.             singer_info_textView = (TextView)findViewById(R.id.singer_info_textView);  
  71.   
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">/*  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">从接收到的广播的intent中取出发送过来的信息  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">这里是取出了歌曲名和艺术家名  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">*/  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">            music_info_textView.setText(intent.getStringExtra("title"));  
  2.             singer_info_textView.setText(intent.getStringExtra("artist"));  
  3.   
  4.         }  
  5.     }  
  6.   
  7.     private class BarReceiver extends BroadcastReceiver{  
  8.         @Override  
  9.         public void onReceive(Context context, Intent intent) {  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">/*  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">取出后,更新进度条当前的位置  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">*/  
  2.                 current_position = intent.getIntExtra("position",0);  
  3.                 seek_bar.setProgress(current_position);  
  4.         }  
  5.     }  
  6. }  


PlayerService.java

[java]  view plain  copy
 print ?
  1. package com.example.dada.myapplication;  
  2.   
  3. import android.app.Notification;  
  4. import android.app.NotificationManager;  
  5. import android.app.PendingIntent;  
  6. import android.app.Service;  
  7. import android.content.BroadcastReceiver;  
  8. import android.content.Context;  
  9. import android.content.Intent;  
  10. import android.content.IntentFilter;  
  11. import android.media.MediaPlayer;  
  12. import android.os.Handler;  
  13. import android.os.IBinder;  
  14. import android.os.Looper;  
  15. import android.os.Message;  
  16. import android.view.animation.AnimationUtils;  
  17. import android.widget.RemoteViews;  
  18.   
  19. import java.io.IOException;  
  20. import java.util.ArrayList;  
  21. import java.util.List;  
  22.   
  23.   
  24. public class PlayerService extends Service implements AppConstant {  
  25.   
  26.     private int current_position;  
  27.   
  28.     private String musicPath;  
  29.     private String music_artist;  
  30.     private String music_title;  
  31.     private String notification_msg;  
  32.   
  33.     private boolean isPause = true;  
  34.     private boolean isChangToNext;  
  35.   
  36. "color:#ff0000;">    private PlayReceiver playReceiver;           //自定义的广播接收器  
  37.   
  38.     public static MediaPlayer mediaPlayer = new MediaPlayer();  
  39.   
  40. "color:#ff0000;">    private Intent intent_to_activity = new Intent("com.example.communication.RECEIVER");   //发送广播的intent  
  41.     private Intent intent_to_progressBar = new Intent("com.example.communication.BAR");  
[java]  view plain  copy
 print ?
  1. "code" class="java" style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">"color:#ff0000;""color: rgb(255, 0, 0); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">/*这里运用到了Handler对各种消息的处理,主要是用它来更新UI  
[java]  view plain  copy
 print ?
  1. "font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;color:#ff0000;">   在下面代码的自定义广播接收器类中,收到消息后,会给这个myHandler发送消息  
[java]  view plain  copy
 print ?
  1. "font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;color:#ff0000;">再由这个myHandler做统一的处理  
[java]  view plain  copy
 print ?
  1. "color: rgb(255, 0, 0); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">*/  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">    private Handler myHandler = new Handler() {                        
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">  
  2.         public void handleMessage(Message msg) {  
  3.             if (msg.what == PlayerMsg.PLAY_MSG) {  
  4.                 current_position = mediaPlayer.getCurrentPosition();  
  5.                 intent_to_progressBar.putExtra("position",  current_position);  
  6.                 sendBroadcast(intent_to_progressBar);  
  7.                 myHandler.sendEmptyMessageDelayed(PlayerMsg.PLAY_MSG, 1000);  
  8.             }  
  9.             if (msg.what == PlayerMsg.PAUSE) {  
  10.                 stopMusic();  
  11.             }  
  12.         }  
  13.     };  
  14.   
  15.     @Override  
  16.     public IBinder onBind(Intent intent) {  
  17.         return null;  
  18.     }  
  19.   
  20.     public int onStartCommand(Intent intent, int flags, int startId) {  
  21.   
  22.         notification_msg = null;  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">/*  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">这里就是前面讲到的接收广播的三部曲  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">*/  
  2.         "color:#ff0000;">playReceiver = new PlayReceiver();  
  3.         IntentFilter intentPlayFilter = new IntentFilter();  
  4.         intentPlayFilter.addAction("com.example.communication.PLAY");  
  5.         registerReceiver(playReceiver, intentPlayFilter);  
  6.   
  7.         try {  
  8.             int msg = intent.getIntExtra("MSG"0);  
  9.             musicPath = intent.getStringExtra("url");  
  10.             "color:#ff0000;">SendBroadcastToActivity(intent);  
  11.   
  12.             if (msg == AppConstant.PlayerMsg.PLAY_MSG) {  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">/*  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">向myHandler发送消息,由myHandler做出处理  
[java]  view plain  copy
 print ?
  1. "color:#ff0000;">*/  
  2.               "color:#ff0000;">  myHandler.sendEmptyMessage(PlayerMsg.PLAY_MSG);    
  3.                 playMusic(0);  
  4.             }  
  5.         } catch (Exception e) {  
  6.             e.printStackTrace();  
  7.         }  
  8.         return 0;  
  9.     }  
  10.   
  11.     private void playMusic(int position) {  
  12.         try {  
  13.             mediaPlayer.reset();  
  14.             mediaPlayer.setDataSource(musicPath);  
  15.             mediaPlayer.prepare();  
  16.             mediaPlayer.setOnPreparedListener(new MyPreparedListener(position));  
[java]  view plain  copy
 print ?
  1.         } catch (IOException e) {  
  2.             e.printStackTrace();  
  3.         }  
  4.     }  
  5.   
  6.     private class MyPreparedListener implements MediaPlayer.OnPreparedListener {  
  7.   
  8.         private int position;  
  9.   
  10.         public MyPreparedListener(int position) {  
  11.             this.position = position;  
  12.         }  
  13.   
  14.         public void onPrepared(MediaPlayer mp) {  
  15.             if (position > 0)  
  16.                 mediaPlayer.seekTo(position);  
  17.             mediaPlayer.start();  
  18.         }  
  19.     }  
  20.   
  21.     private void stopMusic() {  
  22.         if (mediaPlayer != null) {  
  23.             mediaPlayer.pause();  
  24.         }  
  25.     }  
  26.   
  27.     public void onDestory() {  
  28.         if (mediaPlayer != null) {  
  29.             mediaPlayer.stop();  
  30.             mediaPlayer.release();  
  31.         }  
  32.     }  
  33.   
  34.   "color:#ff0000;">  private void SendBroadcastToActivity(Intent intent) {                                //向activity发送广播的函数  
  35.   
  36.         music_title = intent.getStringExtra("title");  
  37.         music_artist = intent.getStringExtra("artist");  
  38.         intent_to_activity.putExtra("title", intent.getStringExtra("title"));  
  39.         intent_to_activity.putExtra("artist", intent.getStringExtra("artist"));  
  40.         intent_to_activity.putExtra("album", intent.getStringExtra("album"));  
  41.         intent_to_activity.putExtra("album_id", intent.getLongExtra("album_id"0));  
  42.         sendBroadcast(intent_to_activity);  
  43.     }  
  44.   
  45.     private class PlayReceiver extends BroadcastReceiver {                             //播放与暂停广播接收器  
  46.   
  47.         public PlayReceiver() {  
  48.             super();  
  49.         }  
  50.   
  51.         @Override  
  52.         public void onReceive(Context context, Intent intent) {  
  53.   
  54.             isPause = intent.getBooleanExtra("isPause"true);  
  55.             isChangToNext = intent.getBooleanExtra("isChangeToNext"false);  
  56.   
  57.             if (isPause) {  
  58.                 myHandler.sendEmptyMessage(PlayerMsg.PAUSE);  
  59.             } else {  
  60.                 current_position = intent.getIntExtra("position"0);  
  61.                 playMusic(current_position);  
  62.                 myHandler.sendEmptyMessage(PlayerMsg.PLAY_MSG);  
  63.             }  
  64.         }  
  65.     }  
  66.   
  67. }  

      上面好长好长的代码,实现的就是能暂停和播放,进度条能显示播放进度,activity能显示歌曲信息,其中包含了两个Broadcast的收发,一个handler的应用.广播在android开发中用的还是比较多的,感觉也是比较好用的哈.

你可能感兴趣的:(Android 音乐播放器的开发教程:运用Broadcast实现service与activity的通信)