AIDL實現不同應用之間跨程序通訊及傳遞與返回各種資料型別和遠端介面回撥
含義:AIDL(Android Interface Definition Language),是android介面定義語言,這種語言定義了一個客戶端和伺服器通訊介面的一個標準、規範。
為什麼要有AIDL?
我們都知道android中的四大元件Activity,Broadcast,Content Provider,Service,前面我們應該都接觸過除了Service的其他三個元件的程序間通訊的例子,比如:一個應用可以通過顯示意圖啟動另外一個Activity,一個應用傳送一個廣播,然後被其他應用所接受,一個應用對外提供一個Content Provider,然後其他應用使用ContentResolver獲取它提供的資料。這些都是程序間通訊的例子(通常情況下每個應用執行在一個獨立的Linux程序中),那麼Service這個元件也同樣也可以實現垮程序通訊
本人工作專案做得是封閉式車載導航系統,各個應用進行資料交換是很常見的事,例如launcher是需要去拿藍芽,收音或者多媒體等資料然後作相應操作,如果在這之間用廣播作資料通訊顯得太low並且也麻煩,所以一般都採用aidl這種方式進行資料交換,當然了 也可以在底層framework應用框架層寫一個介面服務回撥上層,這樣上層每一個應用都可以進行監聽獲取資料,太多理論性的東西這裡不去說,這邊只做aidl的使用說明總結:
server端目錄結構:
關鍵程式碼片段
服務端service類:
public class BTManagerService extends Service implements TimeCallBack {
private IBinder myBinder = new BTBinder();
private IBinder mClientBinder = null;
class BTDeathRecipient implements DeathRecipient {
@Override
public void binderDied() {
System.out.println("---binderDied()--- ");
}
}
private class BTBinder extends IBTService.Stub {
@Override
public void setPinCode(String pincode) throws RemoteException {
System.out.println("---setPinCode()--- " + pincode);
}
@Override
public void setClientBinder(IBinder client) throws RemoteException {
System.out.println("---setClientBinder()--- ");
mClientBinder = client;
mClientBinder.linkToDeath(new BTDeathRecipient(), 0);
}
@Override
public void setDeviceInfo(DeviceInfo deviceInfo) throws RemoteException {
System.out.println("---setDeviceInfo()--- " + deviceInfo.mDeviceName);
}
@Override
public void onRequestAudioFocus() throws RemoteException {
System.out.println("---onRequestAudioFocus()--- ");
}
@Override
public boolean isBTOpen() throws RemoteException {
return false;
}
@Override
public int getA2dpStatus() throws RemoteException {
return 0;
}
@Override
public String getLastTelephone() throws RemoteException {
return "asir";
}
@Override
public PlayStatusInfo getPlayStatusInfo() throws RemoteException {
PlayStatusInfo playStatusInfo = new PlayStatusInfo();
playStatusInfo.mMediaLength = 666;
return playStatusInfo;
}
@Override
public MediaID3Info getMediaID3Info() throws RemoteException {
MediaID3Info mediaID3Info = new MediaID3Info();
mediaID3Info.mMediaTitle = "asir";
return mediaID3Info;
}
@Override
public PhonebookInfo getCurrentRecordInfo() throws RemoteException {
PhonebookInfo phonebookInfo = new PhonebookInfo();
phonebookInfo.mTelephone = "[email protected]";
return phonebookInfo;
}
@Override
public List<DeviceInfo> getDeviceInfoList() throws RemoteException {
List<DeviceInfo> list = new ArrayList<DeviceInfo>();
DeviceInfo d1 = new DeviceInfo();
d1.mDeviceStatus = 1;
DeviceInfo d2 = new DeviceInfo();
d2.mDeviceStatus = 2;
DeviceInfo d3 = new DeviceInfo();
d3.mDeviceStatus = 3;
list.add(d1);
list.add(d2);
list.add(d3);
return list;
}
@Override
public List<PhonebookInfo> getPhonebookList() throws RemoteException {
List<PhonebookInfo> list = new ArrayList<PhonebookInfo>();
PhonebookInfo f1 = new PhonebookInfo();
f1.mTelephone = "1";
PhonebookInfo f2 = new PhonebookInfo();
f2.mTelephone = "2";
PhonebookInfo f3 = new PhonebookInfo();
f3.mTelephone = "3";
list.add(f1);
list.add(f2);
list.add(f3);
return list;
}
@Override
public int onGetMicGainEvent(int[] configs) throws RemoteException {
for (int i : configs) {
System.out.println("-s-" + i);
}
return 0;
}
@Override
public int onSetMicGainEvent(String[] configs) throws RemoteException {
for (String str : configs) {
System.out.println("-s-" + str);
}
return 0;
}
@Override
public void registerCallback(IMediaPlayerListener listener) throws RemoteException {
System.out.println("---registerCallback()---");
if (null != listener && null == mListener) {
MainActivity.getMainActivity().setTimeCallBack(BTManagerService.this);
mListener = listener;
mRemoteCallbackList.register(mListener);
}
}
@Override
public void unregisterCallback(IMediaPlayerListener listener) throws RemoteException {
System.out.println("---unregisterCallback()---");
mRemoteCallbackList.unregister(mListener);
mListener = null;
}
}
private RemoteCallbackList<IMediaPlayerListener> mRemoteCallbackList = new RemoteCallbackList<IMediaPlayerListener>();
private IMediaPlayerListener mListener = null;
@Override
/**
* 媒體播放時間回撥
*/
public void timeChangeCallBack(String poi, String duration) {
try {
mListener.playTimeChangeListener(poi, duration);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
aidl檔案:
package com.asir.aidlserver;
import java.util.List;
import com.asir.aidlserver.DeviceInfo;
import com.asir.aidlserver.PhonebookInfo;
import com.asir.aidlserver.MediaID3Info;
import com.asir.aidlserver.PlayStatusInfo;
import com.asir.aidlserver.IMediaPlayerListener;
interface IBTService {
void setPinCode(String pincode);
void setClientBinder(IBinder client);
void setDeviceInfo(in DeviceInfo deviceInfo);
void onRequestAudioFocus();
boolean isBTOpen();
int getA2dpStatus();
String getLastTelephone();
PlayStatusInfo getPlayStatusInfo();
MediaID3Info getMediaID3Info();
PhonebookInfo getCurrentRecordInfo();
List<DeviceInfo> getDeviceInfoList();
List<PhonebookInfo> getPhonebookList();
int onGetMicGainEvent(inout int[] configs);
int onSetMicGainEvent(inout String[] configs);
void registerCallback(IMediaPlayerListener listener);
void unregisterCallback(IMediaPlayerListener listener);
}
注意事項:
1、客戶端使用時必須要完整拷貝服務端的包及包下的相關AIDL檔案和aidl檔案中引用到的相關物件介面等java檔案
2、對於aidl檔案中用到的物件必須要進行序列化
如程式碼:
public class PhonebookInfo implements Parcelable {
public int mType;
public String mTelephone = null;
public String mUserName = null;
public PhonebookInfo() {
mType = 0;
mTelephone = new String();
mUserName = new String();
}
private PhonebookInfo(Parcel source) {
mType = source.readInt();
mTelephone = source.readString();
mUserName = source.readString();
}
@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
dest.writeString(mTelephone);
dest.writeString(mUserName);
}
public static final Parcelable.Creator<PhonebookInfo> CREATOR = new Parcelable.Creator<PhonebookInfo>() {
@Override
public PhonebookInfo createFromParcel(Parcel source) {
return new PhonebookInfo(source);
}
@Override
public PhonebookInfo[] newArray(int size) {
return new PhonebookInfo[size];
}
};
}
3、傳遞陣列、物件等要用關鍵字(in,inout)
4、客戶端遠端介面回撥用完一定要釋放(unregister)掉,確保clinet端和server端的遠端回撥介面是一樣的,否則會造成記憶體洩露拿不到資料
客戶端目錄結構:
關鍵程式碼片段:
private final class BTConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBTService = IBTService.Stub.asInterface(service);
try {
if (null == mIM) {
mIM = new IMediaPlayerListener.Stub() {
@Override
public void playTimeChangeListener(String poi, String duration) throws RemoteException {
System.out.println(poi + " --- " + duration);
}
};
mBTService.registerCallback(mIM);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBTService = null;
}
}
private void onBindService() {
if (mBTService == null && mBTConnection != null) {
Intent intent = new Intent("com.asir.aidlserver.BTManagerService");
MainActivity.this.bindService(intent, mBTConnection, BIND_AUTO_CREATE);
}
}
private void onUnbindService() {
if (mBTService != null && mBTConnection != null) {
MainActivity.this.unbindService(mBTConnection);
try {
mBTService.unregisterCallback(mIM); // 此處一定要進行資源釋放,否則重新載入時會造成記憶體洩露
} catch (RemoteException e) {
e.printStackTrace();
}
}
mBTService = null;
mBTConnection = null;
}