Android中非aidl实现进程间通信(编写顺序的parcel写入与读出)-成都创新互联网站建设

关于创新互联

多方位宣传企业产品与服务 突出企业形象

公司简介 公司的服务 荣誉资质 新闻动态 联系我们

Android中非aidl实现进程间通信(编写顺序的parcel写入与读出)

在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 mCallbacks = new HashMap();
	/**
	 * 针对某个指令的处理
	 * @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


文章名称:Android中非aidl实现进程间通信(编写顺序的parcel写入与读出)
当前路径:http://kswsj.cn/article/phoseo.html

其他资讯