Android Interface Definition Language (AIDL)
AIDL是允許你完成自定義接口荣茫,用于不同進(jìn)程中服務(wù)器和客戶端之間的通訊宣脉。主要是因?yàn)锳ndroid不允許你直接跨進(jìn)程間傳遞消息财喳,所以需要通過AIDL把傳遞的對(duì)象分解包裝為操作系統(tǒng)可以接受的對(duì)象。
當(dāng)你的Service提供跨進(jìn)程通訊,而且在服務(wù)中做多線程處理時(shí)你可以使用AIDL允扇。如果當(dāng)前的Service不準(zhǔn)備提供給其他進(jìn)程服務(wù)端做訪問你只需要在服務(wù)中實(shí)現(xiàn)自定義的binder即可≡虬拢或者你想實(shí)現(xiàn)IPC(進(jìn)程間通訊)考润,Service內(nèi)又不需要做多線程管理,這種情況下你只要使用Messager读处。當(dāng)然要合理選擇哪一種方式的前提是你清楚了解如何綁定一Service糊治;
設(shè)計(jì)AIDL接口時(shí),要知道你在什么情景下才需要調(diào)用你這個(gè)接口
- 如果只是本地進(jìn)程中調(diào)用這個(gè)接口罚舱,完全沒必要使用AIDL,這時(shí)候只要在服務(wù)中實(shí)現(xiàn)binder即可
- 提供接口給遠(yuǎn)程進(jìn)程井辜,這時(shí)候可能接受遠(yuǎn)程中不同的線程訪問你的接口,換句話說管闷,你要在你的接口中保證線程的安全
- The oneway keyword modifies the behavior of remote calls. When used, a remote call does not block; it simply sends the transaction data and immediately returns. The implementation of the interface eventually receives this as a regular call from the Binder thread pool as a normal remote call. If oneway is used with a local call, there is no impact and the call is still synchronous.
定義AIDL接口
使用java語(yǔ)法在源碼目錄中創(chuàng)建你的 .aidl 文件
當(dāng)你在應(yīng)用中創(chuàng)建了 .aidl 文件粥脚,Android SDK tools 會(huì)基于這個(gè)文件自動(dòng)為我們?cè)?gen/ 目錄中生成IBinder對(duì)象。這樣客戶端就可以通過IBinder實(shí)現(xiàn)IPC通訊
通過AIDL綁定服務(wù)的如下步驟:
創(chuàng)建 .aidl 文件
-
實(shí)現(xiàn)接口
文件自動(dòng)創(chuàng)建接口文件包个,內(nèi)部Stub類必須繼承Binder刷允,實(shí)現(xiàn)Stubd方法內(nèi)的行為
-
對(duì)客戶端暴露接口
實(shí)現(xiàn)的Service重寫 onBind()方法 返回你實(shí)現(xiàn)的stub類
aidl文件的做了任何的改變,切記修改使用你服務(wù)的客戶端
1.創(chuàng)建 .aidl 文件
IRemoteService.aidl
// IRemoteService.aidl
package com.example.administrator.aidl.AIDL;
import com.example.administrator.aidl.AIDL.IRemoteServiceCallback;
// Declare any non-default types here with import statements
interface IRemoteService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void registerCallback(IRemoteServiceCallback cb);
void unregisterCallback(IRemoteServiceCallback cb);
}
ISecondary.aidl
// ISecondary.aidl
package com.example.administrator.aidl.AIDL;
// Declare any non-default types here with import statements
interface ISecondary {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
int getPid();
}
IRemoteServiceCallback.aidl
// IRemoteServiceCallback.aidl
package com.example.administrator.aidl.AIDL;
// Declare any non-default types here with import statements
interface IRemoteServiceCallback {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void valueChanged(int value);
}
實(shí)現(xiàn) .aidl 文件中的接口,如實(shí)現(xiàn) IRemoteService.aidl 和 ISecondary.aidl 接口
創(chuàng)建 .aidl 文件時(shí)碧囊,Android skd Tool 會(huì)自動(dòng)對(duì)應(yīng)的java文件树灶,其中會(huì)生成一個(gè)繼承Binder抽象內(nèi)部類 Stub 。所以在服務(wù)中繼承Stub糯而,實(shí)現(xiàn)自己的內(nèi)部方法天通,例如下面RemoteService中 mBinder和mSecondaryBinder中的實(shí)現(xiàn)
暴露你的接口,例如在例如下面RemoteService中OnBind的方法中歧蒋,把實(shí)現(xiàn)的對(duì)象返回給客戶端程序
RemoteService
public class RemoteService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
if (IRemoteService.class.getName().equals(intent.getAction())) {
return mBinder;
}
if (ISecondary.class.getName().equals(intent.getAction())) {
return mSecondaryBinder;
}
return null;
}
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public void registerCallback(IRemoteServiceCallback cb) throws RemoteException {
cb.valueChanged(mSecondaryBinder.getPid());
}
@Override
public void unregisterCallback(IRemoteServiceCallback cb) throws RemoteException {
}
};
private final ISecondary.Stub mSecondaryBinder = new ISecondary.Stub() {
@Override
public int getPid() throws RemoteException {
return Process.myPid();
}
};
}
綁定方法如同bind方法一樣土砂,bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
public class Binding extends Activity {
private static final int BUMP_MSG = 1;
TextView mCallbackText;
IRemoteService mService;
Button mKillButton;
Boolean mIsBound;
ISecondary mSecondaryService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aidl_layout);
Button bindbutton = (Button) findViewById(R.id.bind);
bindbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Binding.this, RemoteService.class);
intent.setAction(IRemoteService.class.getName());
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
intent.setAction(ISecondary.class.getName());
bindService(intent, mSecondaryConnection, Context.BIND_AUTO_CREATE);
mCallbackText.setText("Binding.");
mIsBound = true;
}
});
Button unbindbutton = (Button) findViewById(R.id.unbind);
unbindbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mIsBound) {
if (mService != null) {
try {
mService.unregisterCallback(mCallback);
} catch (RemoteException e) {
e.printStackTrace();
}
unbindService(mConnection);
mKillButton.setEnabled(false);
mIsBound = false;
mCallbackText.setText("Unbinding");
}
}
}
});
mKillButton = (Button) findViewById(R.id.kill);
mKillButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mSecondaryService != null) {
try {
int pid = mSecondaryService.getPid();
Process.killProcess(pid);
mCallbackText.setText("Killed service process.");
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(Binding.this,
R.string.remote_call_failed,
Toast.LENGTH_SHORT).show();
}
}
}
});
mKillButton.setEnabled(false);
mCallbackText = (TextView) findViewById(R.id.callback);
mCallbackText.setText("Not attached.");
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e("TAG","connected");
mService = IRemoteService.Stub.asInterface(iBinder);
mKillButton.setEnabled(true);
mCallbackText.setText("Attached");
try {
mService.registerCallback(mCallback);
} catch (RemoteException e) {
e.printStackTrace();
}
Toast.makeText(Binding.this, R.string.remote_service_connected,
Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mService = null;
mKillButton.setEnabled(false);
mCallbackText.setText("Disconnected.");
}
};
private ServiceConnection mSecondaryConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mSecondaryService = ISecondary.Stub.asInterface(iBinder);
mKillButton.setEnabled(true);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mSecondaryService = null;
mKillButton.setEnabled(false);
}
};
private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
@Override
public void valueChanged(int value) throws RemoteException {
mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value, 0));
}
};
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BUMP_MSG:
mCallbackText.setText("Received from service: " + msg.arg1);
break;
default:
super.handleMessage(msg);
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
if(mService!=null){
unbindService(mConnection);
}
}
}
IPC傳遞對(duì)象
- 傳遞的對(duì)象實(shí)現(xiàn)Parcelable接口
- 在對(duì)象的類中實(shí)現(xiàn) writeToParcel方法
- 添加一個(gè)靜態(tài)變量CREATOR并且實(shí)現(xiàn)Parcelable.Creator 的接口
- 在目錄中添加一個(gè).aidl文件聲明上面所創(chuàng)建的parcelable 類,列如如下
Rect.aidl
package android.graphics;
parcelable Rect;
這里創(chuàng)建我們的Rect類州既,并實(shí)現(xiàn)現(xiàn)Parcelable接口,類中再實(shí)現(xiàn)writeToParcel方法萝映,靜態(tài)變量CREATOR
Rect.java
public class Rect implements Parcelable {
public int left;
public int top;
public int right;
public int bottom;
public static final Parcelable.Creator<Rect> CREATOR = new Creator<Rect>() {
@Override
public Rect createFromParcel(Parcel parcel) {
return new Rect(parcel);
}
@Override
public Rect[] newArray(int i) {
return new Rect[i];
}
};
public Rect() {
}
private Rect(Parcel in) {
readFromParcel(in);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(left);
parcel.writeInt(top);
parcel.writeInt(right);
parcel.writeInt(bottom);
}
public void readFromParcel(Parcel in) {
left = in.readInt();
top = in.readInt();
right = in.readInt();
bottom = in.readInt();
}
}
在 IRemoteService.aidl添加下面的接口
Rect getRect();
在RemoteService.java中的mBinder對(duì)象中實(shí)現(xiàn)以下方法吴叶,這里我們對(duì)服務(wù)返回的對(duì)象進(jìn)行賦值
@Override
public Rect getRect() throws RemoteException {
Rect rect = new Rect();
rect.bottom = 10;
rect.top = 10;
rect.left = 5;
rect.right = 6;
return rect;
}
這樣我們便可以在客戶端中先服務(wù)獲取我的對(duì)象,具體在Bindnd.java中的mConnection得到Rect對(duì)象序臂,如下
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e("TAG", "connected");
mService = IRemoteService.Stub.asInterface(iBinder);
mKillButton.setEnabled(true);
mCallbackText.setText("Attached");
try {
//獲取到服務(wù)端中的Rect對(duì)象
android.graphics.Rect rectFromService = mService.getRect();
Log.e("TAG","bottom = "+rectFromService.bottom+",top = "+rectFromService.top+",left = "+rectFromService.left+",right ="+rectFromService.right);
mService.registerCallback(mCallback);
} catch (RemoteException e) {
e.printStackTrace();
}
Toast.makeText(Binding.this, R.string.remote_service_connected,
Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mService = null;
mKillButton.setEnabled(false);
mCallbackText.setText("Disconnected.");
}
};