1.服务
当应用程序不再位于前台且没有正在使用它的活动的时候,为了确保音频继续播放,我们需要创建一个服务。服务是安卓应用程序的一个组件,其用于在后台运行任务,而无须与用户交互。
2. 本地服务与远程服务
安卓中存在几个可用的不同服务类。本地服务(Local Service):作为特定应用程序的一部分存在,而且只能通过该应用程序访问和控制。远程服务(Remote Service):是另一种类型的服务,它们可以与其他应用程序进行通信,由其他应用程序访问和控制。在此,仅介绍使用一个本地服务提供音频播放的功能。
3.本地服务
服务类需要继承android.app.Service类。该类是抽象类,所以为了扩展它,必须实现onBind方法。
public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return msBinder;//* }
通常如果只是实现简单服务,并不实现“绑定”的话,可以选择return null。
还有三个表示服务生命周期的方法,onCreate和onDestroy就不用说了,重点说说onStartCommand。每当利用一个匹配服务的意图调用startService时,就会调用onStartCommand方法,因此可能会多次调用它。onStartCommand方法将返回一个整数值,其表示如果结束该服务,那么操作系统应该如何执行操作。可以使用START_STICKY表明如果结束服务,那么将重新启动该服务。
public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.v(TAG,"onStartCommand"); if(!mediaPlayer.isPlaying()) { mediaPlayer.start(); } return START_STICKY; //return super.onStartCommand(intent, flags, startId); }
插一句:从android2.0中引入了onStartCommand方法,在此之前使用的是onStart方法。onStart方法的参数是一个意图和一个表示startId的整数。它不包括int类型的flags参数,而且没有返回值。如果目标电话在2.0之前运行,那么需要使用onStart方法。
注意,别忘了在清单文件中加入一个条目指定该服务。
下一步,我们还希望能够通过活动来控制服务中的MediaPlayer,而发出命令则显得更为复杂。为了控制MediaPlayer,需要利用bindService方法把该活动与服务绑定在一起(解绑定则使用unbindService)。一旦这样做了,由于活动与服务在相同的进程中运行,因此可以直接调用服务中的方法。如果正在创建一个远程服务,那么必须采取更深入一步的步骤。
//启动音乐服务 playMusicServiceIntent=new Intent(this,MusicService.class); startService(playMusicServiceIntent); //serviceConnection是一个ServiceConnection类型的对象,它是一个接口,用于监控所绑定服务的状态 serviceConnection=new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub musicService=null; } //注意该方法传入了一个IBinder对象,其实际上是由服务本身创建并提交的 @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub musicService=((MusicService.MusicServiceBinder)service).getService(); } }; //绑定服务时,需要传入intent和serviceConnection bindService(playMusicServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
我们在服务类中创建了一个私有内部类,其继承自Binder类,在活动中请求连接服务时,用于返回服务本身
public class MusicServiceBinder extends Binder//* { MusicService getService() { return MusicService.this; } }
现在就搭好了基础,可以向服务中添加任何喜欢的功能,同时通过绑定服务,可以直接调用服务中定义的各种方法。如果不绑定服务的话,那么除了启动和停止服务之外,我们将不能做任何其他的事情。
完整代码示例:
活动中的代码:
//启动音乐服务 playMusicServiceIntent=new Intent(this,MusicService.class); startService(playMusicServiceIntent); serviceConnection=new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub musicService=null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub musicService=((MusicService.MusicServiceBinder)service).getService(); } }; //绑定服务 bindService(playMusicServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); //控制音乐服务的按钮 Musicbtn=(Button) findViewById(R.id.musicOn); Musicbtn.setBackgroundResource(R.drawable.musicon); Musicbtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if(musicService.IsPlayNow()) { Musicbtn.setBackgroundResource(R.drawable.musicoff); musicService.PauseMusic(); } else { Musicbtn.setBackgroundResource(R.drawable.musicon); musicService.ResumeMusic(); } } });
服务类代码:
public class MusicService extends Service implements OnCompletionListener { static final String TAG="PLAYERSERVICE"; MediaPlayer mediaPlayer; private final IBinder msBinder=new MusicServiceBinder();//* public class MusicServiceBinder extends Binder//* { MusicService getService() { return MusicService.this; } } @Override public void onCreate() { // TODO Auto-generated method stub //super.onCreate(); Log.v(TAG,"onCreate"); mediaPlayer=MediaPlayer.create(this,R.raw.music); mediaPlayer.setOnCompletionListener(this); } @Override public void onDestroy() { // TODO Auto-generated method stub if(mediaPlayer.isPlaying()) { mediaPlayer.stop(); } mediaPlayer.release(); Log.v(TAG,"onDestroy"); //super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.v(TAG,"onStartCommand"); if(!mediaPlayer.isPlaying()) { mediaPlayer.start(); } return START_STICKY; //return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return msBinder;//* } @Override public void onCompletion(MediaPlayer mediaPlayer) { // TODO Auto-generated method stub //stopSelf(); mediaPlayer.start(); } public void PauseMusic() { if(mediaPlayer.isPlaying()) { mediaPlayer.pause(); } } public void ResumeMusic() { if(!mediaPlayer.isPlaying()) { mediaPlayer.start(); } } public boolean IsPlayNow() { return mediaPlayer.isPlaying(); } }