虽然说这些话不应该讲,但是我只是小小的发一下牢骚,权当发泄吧:自己已经有点适应这样的编码的日子了,甚至非常想要花上一段时间痛快的写一个应用,但是日常的学习的生活还是比较忙率的,而且 最近也听一些讲座,有了很深的启发,归结一点,我觉得比我们年长的程序员对于我们这样的初步的学者还是应该有宽容之心的,但是看到状况还是心中有些难平啊,但是某些评论并不能成为我的阻碍,我还是简单的想要保持一颗简单想要对未知的编码的世界一探究竟的心。
好了言归正传,最近我一直在想着把我的音乐播放器更进一步,所以就我最近的小小的收获写到这里吧。
在上一次的Service的基础上,这次做了“小小”的改进,这里还是专指我需要做的播放器类的Service服务——BrocastReceiver。首先是介于上一次的程序的考虑,如果仅仅是需要一次服务的话,那么我们仅仅需要 在后台启动Service后就没有任何问题,但是这样的Service存在很大的隐患——不能和前台的Activity进行数据的交互,换言之就没有实时的信息,比如我们启动音乐和关闭音乐不仅音乐需要关闭,同时前台也需要更新状态显示音乐的播放或是暂停。这就需要借助于BrocastReceiver来完成通信。
下面是一个简单的MusicBox的演示,这里只是强调功能以及用法完全不涉及其他的界面的考虑。
程序需要使用的Brocastreceiver只需要两步就能够开始启动和注册了。
(1)创建需要启动的Brocastreceiver的Intent。
(2)调用Context的sendBrocast()来指定对应的BrocastReceiver
这些都会在下面的程序中有所体现。需要注意的是当一个程序发出了Brocast Intent之后,所有匹配该Intent的BrocastReceiver都会被启动。
而在实际的理解过程中可以把Brocastreceiver理解为监听器,而要在程序中完成相应的信息的通信,就需要利用Brocast intent来指定,有两种方式:
1.通过在AndroidManifest.xml文件中进行指定:
<receiver android:name=”.xxxxxxReceiver”> <intent-filter> <action android:name=””> </intent-filter> </receiver>
2.通过代码指定
通常是调用BroadcastReceiver的registerReceiver(BrocastReceiver activityReceiver, IntentFilter filter)方法来进行注册绑定,这也是本次博客主要要使用的方法,比较灵活。
下面需要通过一个基于BroadcastReceiver的音乐程序,来阐明service和activity的调用关系。
程序的Service后台负责音乐的播放,当音乐的播放状态需要改变时,可以通过前台的按钮的触发事件来发送消息通知service来改变播放状态。
(一)程序的activity部分较为简单,分为两块:
先看着整体的代码:
package com.musicbox; import android.os.Bundle; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.*; public class MusicBox extends Activity implements OnClickListener{ //界面中的歌曲标题、作者文本框 TextView title,author; //播放、暂停按钮 ImageButton play,stop; // ActivityReceiver activityReceiver=null ; //? public static final String CTL_ACTION = "org.crazyit.action.CTL_ACTION"; public static final String UPDATE_ACTION = "org.crazyit.action.UPDATE_ACTION"; //定义音乐的状态 0x11没有播放 0x12正在播放 0x13停止播放 int status=0x11; //歌曲 String[] titleStrs=new String[]{"心愿","约定","我"}; //演唱 String[] authorStrs=new String[]{"ll","zz","ss"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_music_box); play=(ImageButton)findViewById(R.id.play); stop=(ImageButton)findViewById(R.id.stop); title=(TextView)findViewById(R.id.title); author=(TextView)findViewById(R.id.author); //增加监听事件 play.setOnClickListener(this); stop.setOnClickListener(this); activityReceiver=new ActivityReceiver(); //创建IntentFilter(IntentFilter对象负责过滤掉组件无法响应和处理的Intent) IntentFilter filter=new IntentFilter(); //指定BrocastReceive监听的Action filter.addAction(UPDATE_ACTION); //注册 registerReceiver(activityReceiver, filter); Intent intent=new Intent(this,music_service.class); //启动Service(后台) startService(intent); } @Override public void onClick(View v) { // TODO Auto-generated method stub //向service发送数据 Intent intent =new Intent("org.crazyit.action.CTL_ACTION"); switch(v.getId()) { //按下播放/暂停按钮 case R.id.play: intent.putExtra("control", 1); break; //按下停止按钮 case R.id.stop: intent.putExtra("control", 2); break; } sendBroadcast(intent); } //自定义BroadcastReceiver,负责监听Service传回的广播 public class ActivityReceiver extends BroadcastReceiver { @Override public void onReceive(Context content, Intent intent) { // TODO Auto-generated method stub int update=intent.getIntExtra("update", -1); int current=intent.getIntExtra("current", -1); if(current >=0) { title.setText(titleStrs[current]); author.setText(authorStrs[current]); } switch(update) { case 0x11: play.setImageResource(R.drawable.play); status =0x11; break; case 0x12: play.setImageResource(R.drawable.pause); status= 0x12; break; case 0x13: play.setImageResource(R.drawable.stop); status=0x13; break; } } } }
其中在activity的OnCreated()方法中指定了Brocast intent,这样就绑定了前台的BroadcastReceiver可以用来接收后台service传过来的的信息:
IntentFilter filter=new IntentFilter(); //指定BrocastReceive监听的Action filter.addAction(UPDATE_ACTION); //注册 registerReceiver(activityReceiver, filter); Intent intent=new Intent(this,music_service.class); //启动Service(后台) startService(intent);
同时通过Button的OnClick事件来触发播放和暂停的控制给后台:
public void onClick(View v) { // TODO Auto-generated method stub //向service发送数据 Intent intent =new Intent("org.crazyit.action.CTL_ACTION"); switch(v.getId()) { //按下播放/暂停按钮 case R.id.play: intent.putExtra("control", 1); break; //按下停止按钮 case R.id.stop: intent.putExtra("control", 2); break; } sendBroadcast(intent); }
在代码中自定义BroadcastReceiver,负责监听Service传回的广播.
(二)与之对应的后台的Service的,整体的代码为:
package com.musicbox; 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 music_service extends Service { AssetManager am; //android资源管理框架(这里是音乐文件存储) String[] musics =new String[]{"wish.mp3","promise.mp3" ,"beautiful.mp3"}; MediaPlayer mPlayer; MyReceive serviceReceiver; //当前状态 0x11没有播放 0x12正在播放 0x13停止播放 int status=0x11; //记录当前正在播放放的音乐 int current=0; @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { // TODO Auto-generated method stub am= getAssets(); //创建BroadcastReceiver serviceReceiver=new MyReceive(); mPlayer =new MediaPlayer(); IntentFilter filter=new IntentFilter(); filter.addAction(MusicBox.CTL_ACTION); registerReceiver(serviceReceiver,filter); //MediaPlayer播放完成监听事件 mPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { // TODO Auto-generated method stub current++; if(current>= 3) { current=0; } //通知activity 修改文本框(author..content) Intent sendIntent=new Intent(MusicBox.UPDATE_ACTION); sendIntent.putExtra("current",current); //发送广播 sendBroadcast(sendIntent); // prepareAndPlayer(musics[current]); } }); super.onCreate(); } public class MyReceive extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub int control =intent.getIntExtra("control", -1); switch(control) { //播放或暂停 case 1: if(status ==0x11) { //准备并播放音乐 prepareAndPlayer(musics[current]); status=0x12; //change status } //原来处于播放状态 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; } //广播通知Activity 更改图标 Intent sendIntent =new Intent(MusicBox.UPDATE_ACTION); sendIntent.putExtra("update",status ); sendIntent.putExtra("current", current); //发送广播,将被broadcast接收到 sendBroadcast(sendIntent); } } //播放音乐 private void prepareAndPlayer(String music) { 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 e.printStackTrace(); } } }
同样通过
IntentFilter filter=new IntentFilter(); filter.addAction(MusicBox.CTL_ACTION); registerReceiver(serviceReceiver,filter);
来绑定service与BroadcastReceiver,用来接收前台activity传来的内容。当播放状态改变时(歌曲轮换)service会发送信息被前台service接收,前台service会相应的改变当前的状态。
可以看到程序由于注册了两个BroadcastReceiver的IntentFilter所以就无需在AndroidManifest.xml文件中进行指定。同时程序利用了Service所以支持了程序的音乐后台播放。
(三)程序运行效果:
程序虽然简单,但也确实为我打下一个写service的基础吧,接下来我就可以继续完成我的音乐播放器了。
日进一小步,月过一大步~~加油!!!