Android使用AIDL實(shí)現(xiàn)進(jìn)程間通信
Android的每個應(yīng)用程序都是一個不同的進(jìn)程,在Android平臺一個進(jìn)程通常不能訪問另一個進(jìn)程的內(nèi)存空間。
比如一個應(yīng)用程序有兩個進(jìn)程,一個進(jìn)程負(fù)責(zé)UI的展示,而另一個進(jìn)程(通常是在此進(jìn)程中使用一個service)用來進(jìn)行網(wǎng)絡(luò)資源的請求,需要主進(jìn)程和服務(wù)進(jìn)程之間進(jìn)行數(shù)據(jù)的傳遞。(微信就是使用的這種機(jī)制)
Android提供了AIDL來實(shí)現(xiàn)進(jìn)程間通信(IPC),AIDL全稱為Android Interface Definition Language。
AIDL IPC機(jī)制是面向接口的,使用代理類在客戶端和服務(wù)端之間進(jìn)行數(shù)據(jù)傳遞。那么如何使用AIDL實(shí)現(xiàn)進(jìn)程間通信呢?
使用AIDL實(shí)現(xiàn)IPC服務(wù)需要分別實(shí)現(xiàn)服務(wù)端和客戶端。實(shí)例源碼下載:點(diǎn)擊下載
1、新建aidl文件定義服務(wù)端和客戶端交互的接口(包括數(shù)據(jù)接口);
adil文件定義規(guī)范:
在服務(wù)端的src目錄下新建以.aidl為后綴的文件,在這個文件中定義接口,聲明服務(wù)端和客戶端交互的api,語法和普通java接口聲明一樣,可以添加中英文注釋。
區(qū)別:
a、除了Java基本數(shù)據(jù)類型 (int, long, char, boolean等)、String、CharSequence、List、Map外,其他復(fù)雜類型都需要顯式import(包括其他AIDL定義的接口),即便是在同一個包內(nèi)定義。
b、支持泛型實(shí)例化的List,如List<String>;不支持泛型實(shí)例化的Map,如Map<String, String>。對于List為參數(shù)接收者接收到的始終是ArrayList;對于Map為參數(shù)接收者接收到的始終是HashMap。
c、interface和函數(shù)都不能帶訪問權(quán)限修飾符。
d、接口內(nèi)只允許定義方法,不允許定義靜態(tài)屬性。
- package com.snail.test.aidl.server;
- import com.snail.test.aidl.server.Person;
- interface IAIDLServerService {
- Person getPerson();
- }
aidl文件新建完成后,adt工具會自動編譯aidl文件,大家可以在gen目錄看到對應(yīng)的java文件。
文件中主要有:
a、抽象類Stub,繼承Binder實(shí)現(xiàn)自定義接口,作用同進(jìn)程內(nèi)通信服務(wù)中自定義的Binder,客戶端通過它對服務(wù)進(jìn)行調(diào)用。
b、靜態(tài)類Proxy,實(shí)現(xiàn)自定義接口,代理模式接收對Stub的調(diào)用。
2、新建service實(shí)現(xiàn)定義的接口。
接口中傳遞的對象數(shù)據(jù)需要實(shí)現(xiàn)序列化接口,并且也要定義aidl文件。
- public class AIDLServerService extends Service {
- /**
- * 返回綁定
- */
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
- /**
- * 初始化根據(jù)AIDL文件生成的Stub
- */
- private IAIDLServerService.Stub mBinder = new Stub() {
- /**
- * 實(shí)現(xiàn)定義的接口
- */
- public Person getPerson() throws RemoteException {
- Person mBook = new Person();
- mBook.setName("Snail");
- mBook.setAge(27);
- return mBook;
- }
- };
客戶端:
1、在工程中定義服務(wù)端和客戶端交互的接口,跟服務(wù)端的一模一樣,包名也要一樣,不然會報錯java.lang.SecurityException: Binder invocation to an incorrect interface。
2、通過Stub.asInterface方法獲取服務(wù)來使用定義的接口實(shí)現(xiàn)進(jìn)程間的通信。
- public class MainActivity extends Activity {
- private Button mAIDLBtn;
- private TextView mAIDLView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mAIDLBtn = (Button) findViewById(R.id.aidl_btn);
- mAIDLView = (TextView) findViewById(R.id.aidl_text);
- mAIDLBtn.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- // 綁定服務(wù),這里的service action非常重要,要跟server端定義的action一致
- Intent service = new Intent(
- "com.snail.test.aidl.server.AIDLServerService");
- bindService(service, mConnection, BIND_AUTO_CREATE);
- }
- });
- }
- private IAIDLServerService mIaidlServerService = null;
- /**
- * 服務(wù)連接
- */
- private ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceDisconnected(ComponentName name) {
- mIaidlServerService = null;
- }
- /**
- * 服務(wù)連接成功
- */
- public void onServiceConnected(ComponentName name, IBinder service) {
- mIaidlServerService = IAIDLServerService.Stub.asInterface(service);
- // aidl實(shí)現(xiàn)進(jìn)程間通信
- try {
- Person person = mIaidlServerService.getPerson();
- String str = "姓名:" + person.getName() + "\n" + "年齡:"
- + person.getAge();
- mAIDLView.setText(str);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- };
- }
客戶端和服務(wù)端的service生命周期:
客戶端通過 bindService綁定服務(wù),若服務(wù)未啟動,會先執(zhí)行Service的onCreate函數(shù),再執(zhí)行onBind函數(shù),最后執(zhí)行 ServiceConnection對象的onServiceConnected函數(shù),客戶端可以自動啟動服務(wù)。若服務(wù)已啟動但尚未綁定,先執(zhí)行 onBind函數(shù),再執(zhí)行ServiceConnection對象的onServiceConnected函數(shù)。若服務(wù)已綁定成功,則直接返回。
經(jīng)過以上內(nèi)容的學(xué)習(xí),相信大家已經(jīng)基本掌握了使用AIDL實(shí)現(xiàn)進(jìn)程間通信。