运用Broadcast实现service与activity的通信
做到了这一步,现在的播放器应该可以显示歌曲列表,能够点击并播放音乐了哈,但是上面的按钮一个都不能点啊有没有,一旦放起来停都停不下来,不要着急,这一篇博客将介绍怎么将activity上的按钮都派上用场.
前面介绍过了,播放歌曲是在一个service中进行的,而按钮在activity和fragment上,怎么才能让它们联系起来呢?这就要用到安卓的另外一个四大组件之一----Broadcast,通常翻译为广播(感觉又是怪怪的样子),Broadcast是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver是对发送出来的 Broadcast进行过滤接受并响应的一类组件。这篇将介绍如何实现service和activity的通信.
发送广播的方式很简单,只需要新建一个Intent,里面存放一些需要传出去的信息即可,例如
Intent intent_to_activity = new Intent("com.dada.communication.RECEIVER"); //这个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("com.example.communication.RECEIVER"); //注册歌曲信息的广播接收器,需要与上面发送广播的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 mp3Infos; //歌曲列表
public static int music_position; //音乐的位置
private int current_position; //当前进度条的位置
private ImageButton play_button; //播放按钮控件
private TextView music_info_textView; //显示歌曲信息的textview
private TextView singer_info_textView; //显示歌手信息的textview
private SeekBar seek_bar; //进度条控件
private MsgReceiver msgReceiver; //service发过来的广播接收器
private BarReceiver barReceiver; //进度条的接收器
private Intent intent_to_service; //向service发送广播的intent
/*
这个方法是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);
}
}
}
/*
这个方法是重写了activity里自带的方法onStart()
里面要带上super.onStart();不然会报错的
*/
@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);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
music_position = 0;
current_position = 0;
finder = new FindSongs();
msgReceiver = new MsgReceiver();
barReceiver = new BarReceiver();
mp3Infos = finder.getMp3Infos(getContentResolver());
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);
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);
}
/*
将音乐播放到了的当前位置和当前的状态
以广播的形式发送给service
来让service可以接着刚才暂停的位置开始播放
而不是重新播放
*/
intent_to_service.putExtra("position",current_position);
intent_to_service.putExtra("isPause",isPause);
sendBroadcast(intent_to_service);
}
});
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);
seek_bar.setMax((int)mp3Info.getDuration()); //获取当前播放歌曲的长度,设置进度条的最大值
/*
这里新建了一个Intent
里面存放各种即将传给Service的数据
要启动自定义PlayerService类
还需要在AndroidManifest中加入如下代码
*/
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);
}
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);
/*
从接收到的广播的intent中取出发送过来的信息
这里是取出了歌曲名和艺术家名
*/
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) {
/*
取出后,更新进度条当前的位置
*/
current_position = intent.getIntExtra("position",0);
seek_bar.setProgress(current_position);
}
}
}
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;
private PlayReceiver playReceiver; //自定义的广播接收器
public static MediaPlayer mediaPlayer = new MediaPlayer();
private Intent intent_to_activity = new Intent("com.example.communication.RECEIVER"); //发送广播的intent
private Intent intent_to_progressBar = new Intent("com.example.communication.BAR");
/*这里运用到了Handler对各种消息的处理,主要是用它来更新UI
在下面代码的自定义广播接收器类中,收到消息后,会给这个myHandler发送消息
再由这个myHandler做统一的处理
*/
private Handler myHandler = new Handler() {
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();
}
}
};
@Override
public IBinder onBind(Intent intent) {
return null;
}
public int onStartCommand(Intent intent, int flags, int startId) {
notification_msg = null;
/*
这里就是前面讲到的接收广播的三部曲
*/
playReceiver = new PlayReceiver();
IntentFilter intentPlayFilter = new IntentFilter();
intentPlayFilter.addAction("com.example.communication.PLAY");
registerReceiver(playReceiver, intentPlayFilter);
try {
int msg = intent.getIntExtra("MSG", 0);
musicPath = intent.getStringExtra("url");
SendBroadcastToActivity(intent);
if (msg == AppConstant.PlayerMsg.PLAY_MSG) {
/*
向myHandler发送消息,由myHandler做出处理
*/
myHandler.sendEmptyMessage(PlayerMsg.PLAY_MSG);
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();
}
}
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);
}
}
}
}
上面好长好长的代码,实现的就是能暂停和播放,进度条能显示播放进度,activity能显示歌曲信息,其中包含了两个Broadcast的收发,一个handler的应用.广播在android开发中用的还是比较多的,感觉也是比较好用的哈.