在android中进程间通信(IPC)的基石是Binder系统,Binder系统的核心Binder驱动是C来实现的,对于应用开发人员来说无疑晦涩难懂,而整个android框架是基于面向对象思想的,对于底层Binder驱动的操作细节全部隐藏,framework层提供了一个牛逼无比的Binder对象, 所以我们要实现进程间通信(IPC)只需玩转Binder对象即可。
在android源码中基于Binder对象的通信随处可见,几乎可以认定为以 I 打头的class,都具有进程间通信能力,如:IServiceManager,IContentProvider等。
在源码中实现的方式也可概括为两种:
1. 通过aidl来生成对Binder的操作。
2.手动调用IBinder.transact编写按照顺序写入与读出的parcel代码实现。
第一种方法网上案例较多,不多说。第二种方法实现源码参考:ActivityManagerNative,ActivityManagerProxy
关于第二种方法的实现本人做了一个demo,请看以下代码。
package dw.test;
import java.util.HashMap;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
/**
* 负责接收指令({@link CmdCode}),并将指令派发到相应的处理器({@link CmdDispatcher.Callback})
*/
public final class CmdDispatcher extends Binder implements IInterface{
private static final String LOG_TAG = CmdDispatcher.class.getSimpleName();
public static final String DESCRIPTOR = CmdDispatcher.class.getName();
/**
* 存储所有指令处理器
* map.key = {@link CmdCode}
*/
private HashMap<Integer,Callback> mCallbacks = new HashMap<Integer, Callback>();
/**
* 针对某个指令的处理
* @see #addCallback
* @see #removeCallback
*/
public interface Callback {
/**
* @param code 请求指令集{@link CmdCode.Request},响应 指令集{@link CmdCode.Response}
* @param data 数据 {@link Parcel}
* @param reply 处理data的结果 {@link Parcel}
* @return
*/
public boolean onTransact(int code, Parcel data, Parcel reply);
}
/**
* 当client端调用 {@link IBinder#transact(int, Parcel, Parcel, int)}时,将会回调本方法。
*/
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
dispatch(code,data,reply);
return true;
}
/**
* 得到某个指令处理器并调用
*/
private void dispatch(int code, Parcel data, Parcel reply) {
Log.i(LOG_TAG, "dispatch reply enter");
Callback callback = mCallbacks.get(code);
if(callback!=null){
callback.onTransact(code, data, reply);
}
Log.i(LOG_TAG, "dispatch reply exit");
}
@Override
public IBinder asBinder() {
return this;
}
@Override
public String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public IInterface queryLocalInterface(String descriptor) {
return this;
}
/**
* 针对某一个指令,如:请求指令集{@link CmdCode.Request},响应 指令集{@link CmdCode.Response}
* 添加回调处理
* @param code 指令编码
* @param callback 针对某一个指定的处理 {@link Callback}
*/
public void addCallback(int code,Callback callback) {
mCallbacks.put(code, callback);
}
public void removeCallback(int code) {
mCallbacks.remove(code);
}
}
package dw.test;
/**
* 定义指令集
*/
public interface CmdCode {
public interface BaseCode {
/**
* 每个parcel的头
*/
public static final int PARCEL_HEAD = 0xffff;
public static final int RESULT_SUCCESS = 0x0001;
public static final int RESULT_ERROR = 0x0002;
}
/**
* 请求指令集
*/
public interface Request extends BaseCode{
public static final int REQUEST = 0x0001;
}
/**
* 响应指令集
*/
public interface Response extends BaseCode {
public static final int RESPONSE = 0x0001;
}
}
package dw.test;
import dw.test.CmdDispatcher.Callback;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Parcel;
import android.util.Log;
/**
* RemoteService作为一个独立进程存在.
*/
public class RemoteCmdService extends Service implements Callback,CmdCode.Request{
private static final String LOG_TAG = RemoteCmdService.class.getSimpleName();
private final CmdDispatcher mCmdDispatcher = new CmdDispatcher();
@Override
public IBinder onBind(Intent intent) {
mCmdDispatcher.addCallback(REQUEST, this);
return mCmdDispatcher;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(LOG_TAG, "onStartCommand enter");
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply) {
Log.i(LOG_TAG, "remove service handle Reply enter");
data.enforceInterface(CmdDispatcher.DESCRIPTOR);
//读取包头
int head = data.readInt();
if(head==PARCEL_HEAD) {
String handeResult = data.readString();
reply.writeInt(RESULT_SUCCESS);
Log.i(LOG_TAG, handeResult);
} else {
reply.writeInt(RESULT_ERROR);
}
Log.i(LOG_TAG, "remove service handle Reply exit");
return true;
}
}
package dw.test.activity;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import dw.test.CmdCode;
import dw.test.CmdDispatcher;
import dw.test.R;
import dw.test.RemoteCmdService;
public class MainActivity extends Activity implements OnClickListener , CmdCode.Request,CmdCode.Response{
private static final String LOG_TAG = MainActivity.class.getSimpleName();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.findViewById(R.id.test_remote_binder_btn).setOnClickListener(this);
}
/**
* 连接并调用远程服务
*/
private void testRemote(){
Intent intent = new Intent(MainActivity.this,RemoteCmdService.class);
//绑定远程服务
bindService(intent, new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
replyTo(service);
}
}, BIND_AUTO_CREATE);
}
private void replyTo(IBinder service) {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(CmdDispatcher.DESCRIPTOR);
//写入包头
data.writeInt(PARCEL_HEAD);
//写入要发送的字符数据
data.writeString("serviceConnected");
//当然你也可以传递一个binder对象过去作为callback,这样两个进程间就可以交互了。
// data.writeStrongBinder(IBinder binder);
try {
//调用远程MESSAGE_REQUEST服务
service.transact(REQUEST, data, reply,0);
} catch (RemoteException e) {
//ignore
}
//MESSAGE_REQUEST服务所返回的结果
int result = reply.readInt();
if(RESULT_SUCCESS==result) {
Log.i(LOG_TAG, "ok");
}
data.recycle();
reply.recycle();
}
@Override
public void onClick(View v) {
int id = v.getId();
if(R.id.test_remote_binder_btn==id){
testRemote();
}
}
}
代码工程: http://download.csdn.net/detail/hacker686ok/5810399