AIDL是Android Interface Definition Language的縮寫,意思就是安卓接口定義語言。
IPC是Interprocess Communication的縮寫,意思就是進程間通信。
類似於其他你使用過的接口定義語言,AIDL允許你使用接口來實現客戶端和服務端的進程通信(IPC)。
在Android系統中,一個進程是不能訪問另一個進程的內存的,也就是無法數據或方法共用。所以,我們要把對象分解爲系統可以識別的原始數據,從而達到數據共通。而這個代碼的編寫是非常枯燥和麻煩的。所以Android系統中我們使用AIDL來實現!
注意:如果你要使多個客戶端訪問服務或者要在服務中使用多線程,那麼使用AIDL是必要的。如果你不需要在不同的應用之間執行併發的IPC,那麼是用Binder的方式就夠了。或者你需要實現IPC,但是不需要用到多線程,那麼使用Messenger的方式就可以實現進程通信了。不管怎樣,在使用AIDL之前,你最好已經明白綁定服務的具體作用和含義!
在你開始設計你的AIDL接口前,注意調用AIDL接口使用的函數。你不應該對調用發生的線程做假設。所發生的不同取決於調用是從本地進程或遠程進程中的線程的,例如abc:
a.本地進程中的調用是在同一個線程中執行的。如果這是你的主線程,該線程在AIDL接口中繼續執行。如果是另一個線程,那就是在服務中執行你的代碼。因此,如果只有本地線程訪問服務,你可以完全是用綁定服務的方式來實現就可以了!
b.從一個遠程線程池中調用方法到你自己的進程中。您必須爲來自未知線程的數據同步做準備,同時可能發生在同一時間發生多個回調。意思就是,AIDL接口的實現必須是線程安全的。
c.當調用遠程的數據時,如果遠程服務並沒有阻塞,它僅僅發送數據並立即返回,接口的實現就將定期收到數據,類似於通過遠程服務得到Binder對象!如果只是單獨的使用本地數據,就沒有關係,數據是同步的。
1.定義一個AIDL接口
a.AS創建一個服務端項目(modle)並新建一個.aidl的文件
AS會創建相應目錄並生成一個AIDL文件,在文件中我們寫上自己需要的方法,類似於普通接口
b.然後我們需要使用Build菜單的Make Project,這個操作千萬不要忘記,用於創建aidl相關的java文件。但是在AS的目錄中你是找不到這個java文件的,因爲它隱藏項目構建的debug目錄中,安裝使用的時候纔會添加進去,所以你每修改一次aidl,就需要make project一下!
c.創建一個Service服務,實例化aidl並具體實現其中的方法,通過它的Stub()方法得到stub對象(myBinder),最後在service的onBind()方法中返回它就可以與客戶端建立聯繫了。
d.最後,還需要在AndroidManifest.xml中配置service
2.在客戶端建立AIDL進行通信
a.我們新建一個項目(modle),並把Service中建立的aidl文件連同包都複製過來
b.少不了的,客戶端也需要Make Project
c.在客戶端的一個Activity中,綁定遠程服務,注意setPackage就是服務端apk文件的包名
d.最後,在建立連接的方法中得到IBinder對象,通過它實例化aidl,就可以調用其方法了
package cq.cake.service.client;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import cq.cake.servicetest.IMyAidlInterface;
public class MainActivity extends AppCompatActivity {
public static boolean mBind = false;
@Bind(R.id.tv_text)
TextView tvText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
}
@OnClick(R.id.btn_bindservice)
public void doClick(View view) {
Log.d("TAG", "點擊了綁定 ");
//.首先要綁定服務,這裏的Intent參數就是服務端AndroidManifest.xml中配置的action名稱
Intent intent = new Intent("cq.cake.servicetest.MyAIDL_ACTION");
intent.setPackage("cq.cake.servicetest");
bindService(intent, connection, BIND_AUTO_CREATE);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IMyAidlInterface iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
try {
int result = iMyAidlInterface.plus(50, 50);
String upperStr = iMyAidlInterface.toUpperCase("comes from ClientTest");
tvText.setText("調用遠程服務運行方法後" + "\n" + "50+50 = " + result + "\n"
+ "comes from ClientTest 轉換大寫爲 " + "\n" + upperStr);
} catch (RemoteException e) {
e.printStackTrace();
}
mBind = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBind = false;
}
};
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("TAG", "onDestroy ");
if (mBind) {
unbindService(connection);
mBind = false;
}
}
}
3.實踐:安裝服務端,安裝客戶端。服務端就算沒有啓動,我們也可以通過客戶端來調用服務端的方法。並且多個客戶端共用此服務的方法!
到此關於AIDL進程間通信就介紹完成了,還有不明白的同學可以去看看官方文檔:
https://developer.android.com/guide/components/aidl.html