Android Interface Definition Language,簡稱AIDL,是Android接口定義語言,用於進程間通信。當然你也可以通過發送廣播達到進程間通信的目的,但廣播會碰到延遲等現象,個人建議還是使用AIDL。
AIDL傳輸數據支持Java基本數據類型、List、Map以及實現Parcelable的類。接下來將通過一個實例來講解下AIDL,並支持雙向傳輸,使用Android Studio開發。
AIDL有服務端和客戶端,在服務端,我們先在aidl.com.android.demo路徑下生成一個後綴爲.aidl的DemoInfo.aidl文件,內容如下:
package com.android.demo;
parcelable DemoInfo;
裏面不做什麼,只是定義了一個序列化對象。這是到時候AIDL要傳遞的數據,我們在java.com.android.demo路徑下生成DemoInfo.java去實現。
package com.android.demo;
import android.os.Parcel;
import android.os.Parcelable;
public class DemoInfo implements Parcelable {
private int mValue1 = -1;
private int mValue2 = -1;
public int getValue1() {
return mValue1;
}
public void setValue1(int mValue1) {
this.mValue1 = mValue1;
}
public int getValue2() {
return mValue2;
}
public void setValue2(int mValue2) {
this.mValue2 = mValue2;
}
@Override
public int describeContents() {
return 0;
}
public void readFromParcel(Parcel in) {
mValue1 = in.readInt();
mValue2 = in.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mValue1);
dest.writeInt(mValue2);
}
public static final Creator<DemoInfo> CREATOR = new Creator<DemoInfo>() {
@Override
public DemoInfo createFromParcel(Parcel source) {
DemoInfo mInfo = new DemoInfo();
mInfo.mValue1 = source.readInt();
mInfo.mValue2 = source.readInt();
return mInfo;
}
@Override
public DemoInfo[] newArray(int size) {
return new DemoInfo[size];
}
};
}
接下來,爲了服務端也能向客戶端傳輸數據,我們寫個CallBack,供客戶端去註冊監聽回調。在aidl.com.android.demo路徑下生成一個後綴爲.aidl的DemoCallBack.aidl文件。
package com.android.demo;
import com.android.demo.DemoInfo;
interface DemoCallback {
void sendCtrlData(in DemoInfo info);
}
因爲是傳遞序列化參數,所以AIDL需要我們寫明方向,總共有三種: in , out , inout 。in 表示數據由客戶端流向服務端, out 表示數據由服務端流向客戶端,而 inout 則表示數據可在服務端與客戶端之間雙向流通。接下來我們再在aidl.com.android.demo路徑下生成一個後綴爲.aidl的DemoInterface.aidl文件,內容如下:
package com.android.demo;
import com.android.demo.DemoCallback;
interface DemoInterface {
void getResult(boolean bool);
void registListener(DemoCallback listener);
void unregistListener(DemoCallback listener);
}
裏面寫了供客戶端傳遞數據、註冊監聽回調和釋放監聽回調的接口。接下來服務端要提供 IBinder供客戶端連接,實現如下:
package com.android.demo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
public class AidlService extends Service {
private static AidlService mService = null;
private static RemoteCallbackList<DemoCallback> mListener=new RemoteCallbackList<>();
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
mListener.kill();
}
private DemoInterface.Stub stub = new DemoInterface.Stub() {
@Override
public void getResult(boolean bool) throws RemoteException {
Log.d("AidlService","getResult="+bool);
}
@Override
public void registListener(DemoCallback listener) throws RemoteException {
mListener.register(listener);
}
@Override
public void unregistListener(DemoCallback listener) throws RemoteException {
mListener.unregister(listener);
}
};
public static synchronized AidlService getInstance() {
if (mService == null) {
mService = new AidlService();
}
return mService ;
}
public static void notifyClient(DemoInfo mInfo) throws RemoteException {
int count = mListener.beginBroadcast();
for (int i = 0; i < count; i++) {
DemoCallback broadcastItem = mListener.getBroadcastItem(i);
if (broadcastItem != null) {
try {
//發往客戶端
broadcastItem.sendCtrlData(mInfo);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//一定要記得finishBroadcast
mListener.finishBroadcast();
}
@Override
public IBinder onBind(Intent intent) {
return stub;
}
}
在AndroidManifest.xml中定義下:
<service android:name="com.android.demo.AidlService">
<intent-filter>
<action android:name="com.android.demo.aidl" />
</intent-filter>
</service>
裏面的action是供客戶端綁定時的Intent所要設置的action。至此,服務端的AIDL相關方面就寫好了,現在我們的客戶端要去連接服務端。首先要做的就是把服務端剛纔寫的那些.AIDL複製到客戶端,客戶端路徑要與服務端一致,如服務端是aidl.com.android.demo,那麼客戶端也要是aidl.com.android.demo。然後實現序列化得DemoInfo.java也要複製到客戶端相同位置。現在我們來做連接操作。
package com.android.clinet;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import com.android.demo.DemoCallback;
import com.android.demo.DemoInterface;
import com.android.demo.DemoInfo;
/**
* 服務綁定管理
*/
public class ServiceBindManage implements Handler.Callback{
private final static String TAG = ServiceBindManage.class.getSimpleName();
public static DemoInterface mManagerService = null;
//全局事件服務
private static ServiceBindManage mServiceBindManage = null;
private DemoCallback mListener=new DemoCallback.Stub(){
@Override
public void sendCtrlData(DemoInfo status) throws RemoteException {
Log.d(TAG,"mValue1="+status.getValue1()+",mValue2="+status.getValue2());
}
};
private ServiceConnection mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.d(TAG, "onServiceConnected");
mManagerService = DemoInterface.Stub.asInterface(iBinder);
try {
mManagerService .registListener(mListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mManagerService.unregistListener(mListener);
mManagerService = null;
}
};
public static ServiceBindManage getInstance() {
if (mServiceBindManage == null) {
mServiceBindManage = new ServiceBindManage();
}
return mServiceBindManage;
}
public void bindService(Context ctx) {
Log.d(TAG, "bindService");
//綁定AIDL
bindAidlService("com.android.demo.aidl",mConn);
}
private void bindAidlService(String action, ServiceConnection connent) {
Log.d(TAG, "bindAidlService:Coon = " + connent);
Intent intent = new Intent();
intent.setAction(action);
//服務端包名
intent.setPackage("com.android.demo");
MyApplication.getInstance().bindService(intent, connent, Context.BIND_AUTO_CREATE);
}
public void unBindService(Context ctx) {
if(mManagerService != null){
MyApplication.getInstance().unbindService(mConn);
mManagerService = null;
}
}
}
我們要與服務端綁定AIDL的時候,就調用ServiceBindManage.getInstance().bindService(this);
不需要時,就調用ServiceBindManage.getInstance().unBindService(this);