`
zhy20045923
  • 浏览: 153620 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Binder机制分析【二】-Binder服务/客户端实现举例

阅读更多
前一章说了下Binder机制的实现分析,这章就主要通过实际的例子来看看,具体的服务端创建。一般而言,同一个进程里的沟通称之为短程沟通,进程间的沟通称之为远程沟通,短程沟通的效率远高于远程沟通,但是Android提供的Binder机制就提供了高效率的远程沟通。
下面通过Activity与Service之间的沟通为例,列举出2种实现方式。
例子一:通过直接继承Binder实现
1. 实现Binder类
public class MyBinder extends Binder {
	private Context mContext;
	public MyBinder(Context context){
		mContext = context;
	}
	@Override
	protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
			throws RemoteException {
		reply.writeString(data.readString()+" mp3");
		switch(code){
			case 1:
				MyMediaPlayer.getIntance(mContext).play();
				break;
			case 2:
				MyMediaPlayer.getIntance(mContext).stop();
				break;
			default:
				break;
		}
		return true;
	}
}

该类继承了Binder类,就必须实现onTransact方法,与客户端的transact方法相对应。其中参数code代表客户端调用码,决定在服务器端调用哪个方法,和transact端的保持一致,data是请求参数,由客户端设置,reply为返回参数,服务器端设置。Flags表示ipc通信方式。0表示双向,1表示单向。
2. 实现service类
public class MyService extends Service {
	private Binder mBinder = null;
	@Override
	public IBinder onBind(Intent arg0) {
		Log.e("XXX", "onBind");
		return mBinder;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		mBinder = new MyBinder(this);
		Log.e("XXX", "onCreate");
	}
}

Service相对简单,主要是初始化Binder对象,并且在onBind中返回。
3. Activity与service之间的沟通
首先需要创建ServiceConnection对象,并且在bind时返回Binder对象
private ServiceConnection mServiceConnection = new ServiceConnection() {
		@Override
		public void onServiceDisconnected(ComponentName name) {
			Log.e("XXX", "onServiceDisconnected");
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mIBinder = service;
			Log.e("XXX", "onServiceConnected");
		}
	};

其次,调用bindService绑定服务。
Intent intent = new Intent("com.eric.ipc.binder");
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);

最后,在需要调用服务器端方法的地方,通过transact进行沟通,这里传递的参数必须是Parcel的。
Parcel send_data = Parcel.obtain();
				send_data.writeString("play");
				Parcel reply_data = Parcel.obtain();
					mIBinder.transact(1, send_data, reply_data, 0);

由此可见,这种方法提供的沟通手段比较单一,只能通过transact进行沟通,如果服务器端的接口很多,这样调用起来不太方便,所以Android提供了一种更为简单的方式来实现-AIDL。
AIDL定义了Proxy/Stub封装了IBinder接口,提供了更加方便的新接口。
例子二:通过AIDL实现
1. 单一aidl文件接口
package com.eric.ipc.aidl;
interface IMediaPlayer {
	void play();
	void stop();
}

该接口文件以aidl结尾,中间封装了2个方法,该文件生成后,会在gen目录下自动生成对应的java文件,里面包含了具体的类别继承,反向呼叫等实现。
2. 实现Binder类
public class MyBinder extends IMediaPlayer.Stub {
	private Context mContext;
	public MyBinder(Context context){
		mContext = context;
	}
	@Override
	public void play() throws RemoteException {
		MyMediaPlayer.getIntance(mContext).play();
	}
	@Override
	public void stop() throws RemoteException {
		MyMediaPlayer.getIntance(mContext).stop();
	}
}

现在的实现继承接口改为了aidl类文件的Stub,此处需要实现接口中的2个接口方法
3. 实现service类
此处同例一保持一致
4. activity与service之间的沟通
首先,需要实现ServiceConnection对象,注意返回binder对象时与例一之间的差别。
private ServiceConnection mServiceConnection = new ServiceConnection() {
	   @Override
	   public void onServiceDisconnected(ComponentName name) {
		   Log.e("XXX", "onServiceDisconnected");
	   }
	   
	   @Override
	   public void onServiceConnected(ComponentName name, IBinder service) {
		   mIBinder = IMediaPlayer.Stub.asInterface(service);
		   Log.e("XXX", "onServiceConnected");
	   }
   };

其次,需要绑定服务,方法同例一
最后,具体调用服务器端接口
mIBinder.play();

总结:
2种方法都可以实现跨进程通信,但是aidl实现相对简单,接口直接调用。
问题:
1.如果我们想保持和 Service 的通信,又不想让 Service 随着 Activity 退出而退出呢?你可以先 startService() 然后再 bindService() 。当你不需要绑定的时候就执行 unbindService() 方法,执行这个方法只会触发 Service 的 onUnbind() 而不会把这个 Service 销毁。这样就可以既保持和 Service 的通信,也不会随着 Activity 销毁而销毁了。
2.Activity has leaked ServiceConnection异常
这个异常是由于在启动应用时绑定了service,退出时没有接触绑定导致,可以在退出时调用unbindService()方法解决。
3.在先startService(),然后bindService()的情况下,在退出时
1).如果只调用unbindService(),在第一次会调用onUnbind,然后再次绑定时,通过start启动,再退出是不会调用onUnbind。
2).如果调用unbindService()和stopService,整个service会调用ondestory进行销毁。
3.在通过MediaPlayer播放音乐时,网上都说如果在activity中播放,在activity退出时,音乐播放会停止,这个纯粹是他妈的扯淡,我以前还对此坚信不疑。MediaPlayer播放音乐,会重新启动一个service进行播放,如果你的activity或service已经destory了,是不影响播放service的生命周期的。


例子源码见附件

本章介绍了Binder服务器的实现及举例说明了binder客户端与服务端的交互,下一章介绍下Service是如何绑定Binder的
分享到:
评论
2 楼 zhy20045923 2012-03-13  
nanapoleon 写道
Flags表示ipc通信方式。0表示双向,1表示单向。   这个和aidl的oneway是不是一样的。

这个是不一样的,aidl其实默认的也是0.
oneway的意思是在ipc过程中,如果调用者和被调用者在2个不同的进程,调用者不必等到被调用者返回就继续执行。

以下是引用:The oneway keyword means that if that call results in an IPC (i.e. the caller and callee are in different processes) then the calling process will not wait for the called process to handle the IPC. If it does not result in an IPC (i.e. they're both in the same process), the call will be synchronous. It's an unfortunate detail that simplifies the implementation of binder IPC a lot. If they're in the same process, the call is just a regular java method call.
1 楼 nanapoleon 2012-03-13  
Flags表示ipc通信方式。0表示双向,1表示单向。   这个和aidl的oneway是不是一样的。

相关推荐

Global site tag (gtag.js) - Google Analytics