1、什麼是AIDL
AIDL(Android Interface Definition Language)是一種接口定義語言,編譯器通過*.aidl檔案的描述資訊生成符合通信協定的Java代碼,我們無需自己去寫這段繁雜的代碼,隻需要在需要的時候調用即可,通過這種方式我們就可以完成程序間的通信工作。
2、為什麼要有AIDL
無論學什麼東西,最先得弄明白為什麼要有這個東西,不要說存在即是合理,存在肯定合理,但是你還是沒有明白。對于AIDL有一些人的淺顯概念就是,AIDL可以跨程序通路其他應用程式,和其他應用程式通訊,那我告訴你,很多技術都可以通路,如廣播(應用A在AndroidManifest.xml中注冊指定Action的廣播)應用B發送指定Action的廣播,A就能收到資訊,這樣也能看成不同應用之間完成了通訊(但是這種通訊是單向的);還如ContentProvider,通過URI接口暴露資料給其他應用通路;但是這種都算不上是應用之間的通訊。可能最讓人迷惑的是Android推出來了Messager,它就是完成應用之間的通訊的。那麼為什麼還要有AIDL呢,官方文檔介紹AIDL中有這麼一句話:
Note: Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.
第一句最重要,“隻有當你允許來自不同的用戶端通路你的服務并且需要處理多線程問題時你才必須使用AIDL”,其他情況下你都可以選擇其他方法,如使用Messager,也能跨程序通訊。可見AIDL是處理多線程、多用戶端并發通路的。而Messager是單線程處理。還是官方文檔說的明白,一句話就可以了解為什麼要有AIDL。那麼是不是這樣的寫個AIDL試試。
3、AIDL使用
第一、定義AIDL檔案
/ myServiceAIDL.aidl
package com.haier.oet.androidplayerground;
// Declare any non-default types here with import statements
/** Example service interface */
interface IRemoteService {
/** Request the process ID of this service, to do evil things with it. */
int getPid();
/** Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
這段代碼也是官方文檔的。命名為IRemoteService.aidl,放在com.example.android包下(這個可以随意),儲存後Android編譯器會在gen目錄下自動生成IRemoteService.java檔案。
第二、定義我們的服務,DDService.java,并且需要在AndroidManifest.xml中注冊,并添加“com.haier.oet.test” 的ACTION。
package com.haier.oet.androidplayerground;
/**
* Created by oet on 16/4/22.
*/
import com.haier.oet.androidplayerground.IRemoteService;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Process;
public class DDService extends Service {
@Override
public void onCreate() {
super.onCreate();
System.out.println("DDService onCreate........" + "Thread: " + Thread.currentThread().getName());
}
@Override
public IBinder onBind(Intent arg0) {
System.out.println("DDService onBind");
return mBinder;
}
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
public int getPid(){
System.out.println("Thread: " + Thread.currentThread().getName());
System.out.println("DDService getPid ");
return Process.myPid();
}
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) {
System.out.println("Thread: " + Thread.currentThread().getName());
System.out.println("basicTypes aDouble: " + aDouble +" anInt: " + anInt+" aBoolean " + aBoolean+" aString " + aString);
}
};
}
AndroidManifest.xml中注冊
<service android:name=".DDService"
android:process="com.haier.oet.test">
<intent-filter>
<action android:name="com.haier.oet.test" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
這樣我們的服務端就完成了,把服務端運作到模拟器(或者手機上),等一會可以看一下列印資訊,重點看“線程名”。
第三、實作用戶端測試代碼 建立另一個工程,同樣需要添加AIDL協定檔案(這是一個标準的協定檔案,定義對外服務),這裡我列出來我的測試代碼:
package com.haier.oet.androidplayerground;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.view.View;
public class MainActivity3 extends Activity {
private IRemoteService remoteService;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
remoteService = IRemoteService.Stub.asInterface(service);
try {
int pid = remoteService.getPid();
int currentPid = Process.myPid();
System.out.println("currentPID: " + currentPid +" remotePID: " + pid);
remoteService.basicTypes(12, 1223, true, 12.2f, 12.3, "我們的程式,我明白");
} catch (RemoteException e) {
e.printStackTrace();
}
System.out.println("bind success! " + remoteService.toString());
}
};
/**
* 監聽按鈕點選
* @param view
*/
public void buttonClick(View view) {
Intent intent = new Intent();
intent.setAction("com.haier.oet.test");
intent.setPackage("com.haier.oet.androidplayerground"); //指定啟動的是那個應用(com.haier.oet.test)中的Action(com.haier.oet.androidplayerground)指向的服務元件
bindService(intent, conn, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
4、執行,點選用戶端按鈕,執行,看列印資訊:

看服務端列印,DDService onCreate..........Thread: main,主線程,當用戶端調用服務端getPid方法時,服務端是在Thread: Binder2中執行,當用戶端調用服務端basicType方法時,服務端是在Thread:Binder1中執行。