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();
}
}