通常每个应用程序都在它自己的进程内运行,但有时需要在进程之间传递对象(IPC通信),你可以通过应用程序UI的方式写个运行在一个不同的进程中的service。在android平台中,一个进程通常不能访问其它进程中的内存区域。所以,他们需要把对象拆分成操作系统能理解的简单形式,以便伪装成对象跨越边界访问。编写这种伪装代码相当的枯燥乏味,好在android为我们提供了AIDL工具可以来做这件事。
AIDL(android接口描述语言)是一个IDL语言,它可以生成一段代码,可以使在一个android设备上运行的两个进程使用内部通信进程进行交互。如果你需要在一个进程中(例如在一个Activity中)访问另一个进程中(例如一个Service)某个对象的方法,你就可以使用AIDL来生成这样的代码来伪装传递各种参数。
要使用AIDL,Service需要以aidl文件的方式提供服务接口,AIDL工具将生成一个相应的java接口,并且在生成的服务接口中包含一个功能调用的stub服务桩类。Service的实现类需要去继承这个stub服务桩类。Service的onBind方法会返回实现类的对象,之后你就可以使用它了,参见下例:
IMusicControlService.aidl
- package com.homer.remote;
- interface IMusicControlService{
- void play();
- void stop();
- void pause();
- }
- public class RemoteMusicService extends Service {
- private MediaPlayer mediaPlayer;
- @Override
- public IBinder onBind(Intent intent) {
- return binder;
- }
- private final IMusicControlService.Stub binder = new IMusicControlService.Stub() {
- @Override
- public void play() throws RemoteException {
- if (mediaPlayer == null) {
- mediaPlayer = MediaPlayer.create(RemoteMusicService.this, R.raw.tmp);
- mediaPlayer.setLooping(false);
- }
- if (!mediaPlayer.isPlaying()) {
- mediaPlayer.start();
- }
- }
- @Override
- public void pause() throws RemoteException {
- if (mediaPlayer != null && mediaPlayer.isPlaying()) {
- mediaPlayer.pause();
- }
- }
- @Override
- public void stop() throws RemoteException {
- if (mediaPlayer != null) {
- mediaPlayer.stop();
- try {
- mediaPlayer.prepare(); // 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数
- } catch (IOException ex) {
- ex.printStackTrace();
- }
- }
- }
- };
- @Override
- public void onDestroy() {
- super.onDestroy();
- if(mediaPlayer != null){
- mediaPlayer.stop();
- mediaPlayer.release();
- }
- }
- }
客户端(Activity)应用连接到这个Service时,onServiceConnected方法将被调用,客户端就可以获得IBinder对象。参看下面的客户端onServiceConnected方法:
Activity
- public class PlayRemoteMusic extends Activity implements OnClickListener {
- private Button playBtn;
- private Button stopBtn;
- private Button pauseBtn;
- private Button exitBtn;
- private IMusicControlService musicService;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.remote_music_service);
- playBtn = (Button) findViewById(R.id.play);
- stopBtn = (Button) findViewById(R.id.stop);
- pauseBtn = (Button) findViewById(R.id.pause);
- exitBtn = (Button) findViewById(R.id.exit);
- playBtn.setOnClickListener(this);
- stopBtn.setOnClickListener(this);
- pauseBtn.setOnClickListener(this);
- exitBtn.setOnClickListener(this);
- connection();
- }
- private void connection() {
- Intent intent = new Intent("com.homer.remote.remoteMusicReceiver");
- bindService(intent, sc, Context.BIND_AUTO_CREATE); // bindService
- }
- @Override
- public void onClick(View v) {
- try {
- switch (v.getId()) {
- case R.id.play:
- musicService.play();
- break;
- case R.id.stop:
- if (musicService != null) {
- musicService.stop();
- }
- break;
- case R.id.pause:
- if (musicService != null) {
- musicService.pause();
- }
- break;
- case R.id.exit:
- this.finish();
- break;
- }
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- private ServiceConnection sc = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) { //connect Service
- musicService = IMusicControlService.Stub.asInterface(service);
- }
- @Override
- public void onServiceDisconnected(ComponentName name) { //disconnect Service
- musicService = null;
- }
- };
- @Override
- public void onDestroy(){
- super.onDestroy();
- if(sc != null){
- unbindService(sc); // unBindService
- }
- }
- }
Remote Service流程总结:
1、 Activity(客户端)中,Intent intent = new Intent("com.homer.remote.remoteMusicReceiver");构建intent,然后bindService(intent, sc, Context.BIND_AUTO_CREATE);绑定服务
2、 Activity(客户端)中,通过ServiceConnection()重载onServiceConnected()建立连接,获取Service.Stub实例;onServiceDisconnected()释放连接(与bindService类似)
3、 Service中,通过重载onBind(Intent intent) 返回Service.Stub实例,但Service.Stub类是由aidl文件生成的接口类中的一个内部类Stub类,Service来继承该Stub类
4、 Activity中,通过操作Service实例(musicService),执行音乐播放操作(play、pause、stop等)