前言:闲着也是闲着,不如多学点东西
下面的程序开发了一个基于Service组件的音乐盒,程序的音乐将会由后台运行的Service组件负责播放,当后台的播放状态发生改变时,程序将会通过发生广播通知前台Activity更新界面;当用户单击前台Activity的界面按钮时,系统将通过发送广播通知后台Service来改变播放状态。
Activity界面代码如下:
package com.example.musicproject; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageButton; import android.widget.TextView; public class MainActivity extends Activity implements OnClickListener{ private TextView title,author; private ImageButton play,stop; ActivityReceiver activityReceiver; public static final String CTL_ACTION="org.crazyit.action.CTL_ACTION"; public static final String UPDATE_ACTION="org.crazyit.action.UPDATE_ACTION"; //定义音乐的播放状态 int status = 0x11; String[] titleStrs = new String[]{"心愿","约定","美丽"}; String[] autorStrs = new String[]{"未知艺术照","作者1","作者2"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); title = (TextView) findViewById(R.id.title); author = (TextView) findViewById(R.id.author); play = (ImageButton) findViewById(R.id.play); stop = (ImageButton) findViewById(R.id.stop); play.setOnClickListener(this); stop.setOnClickListener(this); //广播 IntentFilter filter = new IntentFilter(); filter.addAction(UPDATE_ACTION); registerReceiver(activityReceiver, filter); //服务 Intent intent = new Intent(this,MusicService.class); startService(intent); } //自定义的BroadcastReceiver,负责监听从service传回来的广播 public class ActivityReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // 获取Intent中的update消息,update代表播放状态 int update = intent.getIntExtra("update", -1); //获取Intent中的current消息,current代表正在播放的歌曲 int current = intent.getIntExtra("current", -1); if(current>=0){ title.setText(titleStrs[current]); author.setText(autorStrs[current]); } switch (update) { case 0x11: play.setImageResource(R.drawable.button_grey_play); status = 0x11; break; //进入播放 case 0x12: play.setImageResource(R.drawable.gnome_session_suspend); status = 0x12; break; //进入暂停 case 0x13: play.setImageResource(R.drawable.button_grey_play); status = 0x13; break; default: break; } } } @Override public void onClick(View v) { // 创建Intent Intent intent = new Intent("org.crazyit.action.CTL_ACTION"); switch (v.getId()) { //按下播放、暂停按钮 case R.id.play: intent.putExtra("contorl", 1); break; //按下停止按钮 case R.id.stop: intent.putExtra("contorl", 2); break; default: break; } } }
上面代码关键地方有2处。
1)在ActivityReceiver中,代码主要用于相应后台Service所发出的广播,该程序将会根据广播Intent里的消息来改变播放状态,并更新程序界面中按钮的图标;当正在播放时,显示暂停图标;当正在暂停时,显示播放图表。并根据传回来的current数据来更新title.author两个文本框所显示的文本------显示当前正在播放的歌曲的歌名和歌手。
2)第二段粗体代码则根据用户单击的按钮发送广播,发送广播时会把所按下的按钮的标识发送出来。发送的广播将激发后台Service的BroadcastReceiver,该BroadcastReceiver将会根据广播消息来改变播放状态。
与之对应收到是,该程序的后台Service也一样,他会在播放状态发生改变时对外发送广播;它也会采用BroadcastReceiver监听来自前台Activity所发出的广播。
package com.example.musicproject; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.os.IBinder; public class MusicService extends Service{ MyReceiver serviceReceiver; AssetManager am; String[] musics = new String[]{"wish.mp3","promise.mp3","beautiful.mp3"}; MediaPlayer mPlayer; //当前的状态,0x11表示没有播放,0x22表示正在播放,0x33表示暂停 int status = 0x11; //记录当前正在播放的音乐 int current = 0; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { am = getAssets(); //创建BroadcastReceiver serviceReceiver =new MyReceiver(); //创建IntentFilter IntentFilter filter = new IntentFilter(); filter.addAction(MainActivity.CTL_ACTION); registerReceiver(serviceReceiver, filter); //创建MediaPlayer mPlayer = new MediaPlayer(); //为MediaPlayer播放完成事件绑定监听器 mPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { // TODO Auto-generated method stub current++; if(current >=3){ current = 0; } //发送广播通知Activity更改文本框 Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION); sendIntent.putExtra("current", current); //发送广播,将被Activity组件中的BroadcastReceiver接收到 sendBroadcast(sendIntent); //准备并播放音乐 prepareAndPlay(musics[current]); } }); super.onCreate(); } private void prepareAndPlay(String music) { // TODO Auto-generated method stub try { //打开指定音乐文件 AssetFileDescriptor afd = am.openFd(music); mPlayer.reset(); //使用MediaPlayer加载指定的声音文件 mPlayer.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength()); //准备声音 mPlayer.prepare(); //播放 mPlayer.start(); } catch (Exception e) { // TODO: handle exception } } public class MyReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { int control = intent.getIntExtra("control", -1); switch (control) { case 1: //原来处于没有播放状态 if(status == 0x11){ prepareAndPlay(musics[current]); status = 0x12; } //原来处于播放状态 else if(status == 0x12){ //暂停 mPlayer.pause(); //改变为暂停状态 status = 0x13; } //原来处于暂停状态 else if(status == 0x13){ //播放 mPlayer.start(); //改变状态 status= 0x12; } break; case 2: //如果原来正在播放或者正在播放或者暂停状态 if(status == 0x12 || status == 0x13){ //停止播放 mPlayer.stop(); status=0x11; } break; default: break; } //广播通知Activity更改图标,文本框 Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION); sendIntent.putExtra("update", status); sendIntent.putExtra("current", current); //发送广播,将被Activity组件中的BroadcastReceiver接收到 sendBroadcast(sendIntent); } } }
除此之外,为了让该程序能按顺序依次播放每首歌曲,程序为MediaPlayer增加了ONCompletionListener监听器,当MediaPlayer播放完成后将让它自动播放下一首歌曲。