Android 跨进程通信: AIDL
概念
在Android上一個進程通常是無法訪問另一個進程的內存,而AIDL翻譯過來就是Android 接口定義語言,你可以你利用它定義客戶端和服務端進程間通信相互認可的編程接口。
適用范圍
只有允許不同應用的客戶端用IPC方式訪問服務,并且想要在服務中處理多線程問題時,才有必要適用AIDL。如果想執行IPC,但不需要處理多線程,可以考慮使用Messenger類實現。如果不需要執行跨不同應用的并發IPC,可以通過實現一個Binder來實現。
使用
考慮這樣一個場景:client 客戶端跨進程訪問 server 客戶端,流程如下
server 客戶端接受請求通知,訪問遠程服務器返回數據,并將數據通知給client 客戶端 , 下面我們來看看如何一步步實現該功能
創建server 客戶端
1、創建.aidl文件
新建一個名為server的工程,這里面我們創建三個aidl文件
IRomteService.aidl 定義請求接口
ICallBack.aidl 自定義回調接口
MyBean.aidl 自定義的對象
MyBean.java 自定義對象類(必須實現Parcelable接口)
注意:MyBean.aidl和MyBean.java要保證在同一個包路徑下
// IRomteService.aidl package com.aidlserver.myaidl; import com.aidlserver.myaidl.MyBean; import com.aidlserver.myaidl.ICallBack; // Declare any non-default types here with import statementsinterface IRemoteService {void requestServer(in MyBean param, in ICallBack callback); } // MyBean.aidl package com.aidlserver.myaidl; import com.aidlserver.myaidl.MyBean; // Declare any non-default types here with import statementsparcelable MyBean; // ICallBack.aidl package com.aidlserver.myaidl; // Declare any non-default types here with import statementsinterface ICallBack {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/void onResult(String result); } package com.aidlserver.myaidl;import android.os.Parcel; import android.os.Parcelable;public class MyBean implements Parcelable {public int mId;public String mName;public MyBean() {}protected MyBean(Parcel in) {readFromParcel(in);}public static final Creator<MyBean> CREATOR = new Creator<MyBean>() {@Overridepublic MyBean createFromParcel(Parcel in) {return new MyBean(in);}@Overridepublic MyBean[] newArray(int size) {return new MyBean[size];}};@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(mId);dest.writeString(mName);}public void readFromParcel(Parcel in) {mId = in.readInt();mName = in.readString();}@Overridepublic String toString() {return "id:" + mId + " name:" + mName;} }2、創建Service(關鍵部分)
創建一個RemoteService服務,它是連接外部應用和遠程服務器的樞紐,代碼如下
package com.aidlserver.service;import android.app.Service; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; import android.support.annotation.Nullable; import android.util.Log;import com.aidlserver.myaidl.ICallBack; import com.aidlserver.myaidl.IRemoteService.Stub; import com.aidlserver.myaidl.MyBean;public class RemoteService extends Service {private static final String TAG = RemoteService.class.getSimpleName();private static final String CLIENT_PACKAGE_NAME = "com.client";private static final String MYSELF_PACKAGE_NAME = "com.aidlserver";private Object mLock = new Object();@Overridepublic void onCreate() {super.onCreate();Log.d(TAG, TAG + "onCreate");}private Stub mBinder = new Stub() {@Overridepublic void requestServer(MyBean param, final ICallBack callback) throws RemoteException {synchronized (mLock) {//模擬耗時請求開啟線程請求服務端Log.d(TAG, "requestServer param:" + param.toString());new Thread(new Runnable() {@Overridepublic void run() {if (callback != null) {try {callback.onResult("I was server response . hello client");} catch (RemoteException e) {e.printStackTrace();}}}}).start();}}//該方法可以對外部應用做認證@Overridepublic boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {String[] stringArray = RemoteService.this.getPackageManager().getPackagesForUid(getCallingUid());String packageName = null;if (stringArray != null && stringArray.length > 0) {packageName = stringArray[0];}boolean result = false;//只有"com.client"應用及其自己能訪問if (!CLIENT_PACKAGE_NAME.equals(packageName)&& !MYSELF_PACKAGE_NAME.equals(packageName)) {result = false;} else {result = super.onTransact(code, data, reply, flags);}Log.d(TAG, "packageName:" + packageName + " result:" + result);return result;}};@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.d(TAG, "=====onBind=====");//返回自定義的IRemoteService的存根(Sub)return mBinder;}@Overridepublic void unbindService(ServiceConnection conn) {super.unbindService(conn);Log.d(TAG, "=====unbindService=====");}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG, "=====onDestroy=====");} }3、注冊Service
在清單文件加入如下代碼
<application><serviceandroid:name=".service.RemoteService"android:enabled="true"android:exported="true"android:process=":remote"></service> </application>4、編寫客戶端調用代碼
新建一個Activity,
完整Activity代碼如下,
現在我們運行server app 效果如下:
創建Client 客戶端
client客戶端代碼就比較簡單了,
我們只要把server工程里面
ICallBack.aidl
IRemoteService.aidl
MyBean.aidl
MyBean.java移到和server同一個包路徑就可以了,
client客戶端調用的activity和server客戶端的activity幾乎一樣
源碼下載:
AIDL Demo
總結
以上是生活随笔為你收集整理的Android 跨进程通信: AIDL的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android-源码剖析CountDow
- 下一篇: Mac 解压Android NDK.bi