这只是一个小例子,实现三首mp3格式音乐的循环播放,并且有播放、暂停、停止的功能。

大体思想:

  1. 需要一个Activity用来与用户交互当前播放情况,用户通过点击按钮操作播放、暂停和停止。
  2. 还需要有一个后台Service处理音乐的播放(还好Android有MediaPlayer对象可以对音乐进行播放、暂停等操作)。
  3. Activity和Service之间需要进行交互,
    (1)用户点击按钮执行音乐的播放、暂停或者停止,每一个按钮对应一种状态,通过Broadcast广播传给Service。
    (2)Service接收Activity发来的广播,对操作进行判断从而执行MediaPlayer的音乐操作。之后将音乐的信息同样以广播的形式发送回Activity。
    (3)Activity接收Service的广播在页面上更新歌曲的信息。

下面是细节的问题:

1.首先Activity布局非常简单,一个文本框用来显示歌曲名,两个按钮,“播放”和“停止”。

2.然后是Activity:

(1)onCreate()方法:

其实最主要的两件事是创建BroadcastReceiver对象、Intent过滤器和Receiver的注册(Broadcast不同于监听器,Broadcast是一个系统级的监听器,拥有自己的进程,因此只要存在与之匹配的Intent被广播出来,BroadcastReceiver总会被触发),然后开启后台的Service。

ar = new ActivityReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(UPDATE_ACTION); //update更改界面播放信息
getApplicationContext().registerReceiver(ar,filter);
Intent in = new Intent(MainActivity.this,MP3Service.class);
startService(in); //开启Service

 

(2)定义BroadcastReceiver的子类并重写onReceive方法,这是Service发送歌曲信息的广播,然后Activity获取并更新页面的Receiver:onReceive方法在应用发送相应广播后自动执行,执行之后BroadcastReceiver实例就会被销毁。

public class ActivityReceiver extends BroadcastReceiver{
  
        @Override
        public void onReceive(Context context, Intent intent) {
            System.out.println("activity receive");
            int update = intent.getIntExtra("update", -1);
            int current = intent.getIntExtra("current", -1);
            if(current>=0){
                title.setText(titleStrs[current]);
            }
            switch(update){
            case 0x11:
                play.setText(R.string.play);
                break;
            case 0x12:
                play.setText(R.string.pause);
                break;
            case 0x13:
                play.setText(R.string.play);
                break;
            }
        }
          
    }

(3)onClick:首先Activity有两个按钮,定义一个control状态代表哪个按钮被执行,播放和暂停是一类的,停止是第二类的,将哪个按钮被执行的control状态封装到Intent中,然后发送广播给Service。

public void onClick(View source) {
    Intent in = new Intent(CTL_ACTION); //Service中广播处理的是CTL_ACTION的Intent
    switch(source.getId()){
    case R.id.play:
        in.putExtra("control", 1);
        break;
    case R.id.stop:
        in.putExtra("control", 2);
        break;
    }
    sendBroadcast(in);//发送广播到service
    System.out.println("activity send");
}

 

(4)onDestroy:最后,因为Service是Activity开启的,而且同样在onCreate中注册了BroadcastReceiver,因此当Activity被销毁时,也需要将Service和BroadcastReceiver释放:

protected void onDestroy() {
    stopService(in);
    getApplicationContext().unregisterReceiver(ar);
    super.onDestroy();
}

3.接着是Service:

(1)onCreate:创建MediaPlayer对象,为MediaPlayer设置CompletingListener监听器(当前数据被播放完之后执行,用来播放下一首),创建AssetManager对象用于读取sdcard的音乐文件,并创建接收Activity广播的BroadcastReceiver:

asset = getAssets();
mr = new MyReceiver();
IntentFilter filter = new IntentFilter(MainActivity.CTL_ACTION); //控制播放
getApplicationContext().registerReceiver(mr,filter);
mp = new MediaPlayer();

 

(2)MediaPlayer的监听器:根据current当前歌曲的标号进行歌曲的切换,并发送下一首歌曲的信息通过广播发送给Activity:

mp.setOnCompletionListener(new OnCompletionListener(){
  
            @Override
            public void onCompletion(MediaPlayer mp) {
                current = current+1; //从0开始的,0,1,2三首
                if(current>=3){
                    current = 0;
                }
                //通知界面更新歌曲信息
                Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION);
                sendIntent.putExtra("current", current);
                sendBroadcast(sendIntent);
                prepareAndPlay(songs[current]);
            }
              
        });

 

(3)最重要的接收Activity中用户点击按钮的状态发来的广播进行音乐播放处理的Receiver:

public class MyReceiver extends BroadcastReceiver{
  
        @Override
        public void onReceive(Context context, Intent intent) {
            System.out.println("serivce receive");
            int control = intent.getIntExtra("control",-1);
            switch(control){
            case 1: //播放或暂停
                if(status==0x11){
                    prepareAndPlay(songs[current]);
                    status = 0x12;
                }
                else if(status==0x12){
                    mp.pause();
                    status = 0x13;
                }
                else if(status==0x13){
                    mp.start();
                    status = 0x12;
                }
                break;
            case 2: //停止音乐
                if(status==0x12||status==0x13){
                    mp.stop();
                    status = 0x11;
                }
            }
            Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION);
            sendIntent.putExtra("current",current);
            sendIntent.putExtra("update", status);
            sendBroadcast(sendIntent);
            System.out.println("service send");
        }
          
    }

 

(4)最后在onDestroy中释放Receiver:

public void onDestroy() {
        System.out.println("ondestroy");
        getApplicationContext().unregisterReceiver(mr);
        super.onDestroy();
    }

(5)有一个细节,就是在播放完一个歌曲之后,再播放下一个的时候,MediaPlayer对象一定要执行reset方法,不然会发生MediaPlayer状态的异常。以下是prepareAndPlay方法:

 

public void prepareAndPlay(String music){
        try{
            File f = new File(Environment.getExternalStorageDirectory()+"/"+music);
            if(f.exists()){
                System.out.println("--cunzai--");
            }
            //AssetFileDescriptor afd = asset.openFd(Environment.getExternalStorageDirectory()+"/"+music);
            try {
                mp.reset(); //在执行新的一次play的时候需要reset
                mp.setDataSource(Environment.getExternalStorageDirectory()+"/"+music);
                mp.prepare();
                mp.start();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }catch(Exception e){
              
        }
    }

4.最后别忘记在Manifest文件中配置Service,由于Receiver是在代码中生成的,因此无需进行配置。