Android 音乐播放器的开发教程(七)运用Broadcast实现service与activity的通信 ----- 小达

运用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>

</pre><pre name="code" class="java" style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;"><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开发中用的还是比较多的,感觉也是比较好用的哈.



  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值