您好,登錄后才能下訂單哦!
在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
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。