A. android之AIDL
AIDL 是 Android 跨進程通信的一種方式
所有的非基本參數都需要一個定向 tag 來指出數據的流向,不管是 in , out , 還是 inout 。基本參數的定向 tag 默認是並且只能是 in
Book.kt
Book.aidl
IOnNewBookArrivedListener.aidl 用於添加監聽
客戶端發起遠程請求,會調用 IBookManager.Stub.Proxy 的對應實現方法,在這個方法里,創建了 Parcel 對象 _data、輸出型 Parcel 對象 _reply 和返回值對象 List,將參數寫入 _data 中,調用 transact 方法來發起 RPC ,同時當前線程掛起,然後服務端的 onTransact 方法會被調用,在 onTransact 中,調用服務端提供的服務方法,寫入結果,回到客戶端的 transact ,將結果從 _reply 讀出並返回
B. Android:AIDL進程間通信基本框架
在某些業務場景下,我們需要在應用中單獨開啟一個進程進行一些操作。比如性能監控,如果讓原始業務和性能監控本身的業務跑在同一個進程下,那麼就會導致性能統計的數據的失真。
而進程間通信,一般採用AIDL機制的客戶端與服務端通信。
AIDL只能傳遞如下幾類數據:
當傳遞自定義 Parcelable 時,有三處地方需要注意:
當傳遞其他 aidl 介面時,同樣必須要 import 這個 aidl 文件
編寫完 aidl 文件後,make一下工程,會在 build 下的 generated 下的 source 下的 aidl 目錄生成對應的介面類文件。aidl 介面其實就是 API 介面,通過實現對應介面類的 Stub 子類來實現具體的 API 邏輯;通過對應介面類的 Stub 子類的 asInterface 方法得到具體的實現類,調用具體的 API 方法。
一個基本的客戶端服務端的通信結構一般包括如下功能
客戶端的功能
服務端的功能
客戶端的相關功能實現比較簡單,麻煩的是服務端的功能。因為 AIDL 介面定義的都是服務端的介面,是由客戶端來調用的。而想要實現服務端反向調用客戶端則需要通過其他手段實現。
想要實現服務端主動連接客戶端,最好的辦法就是 服務端發送廣播,客戶端收到廣播後再主動連接服務端 ,通過這種方式變相地實現服務端主動連接客戶端的功能
想要實現服務端主動斷開客戶端,除了上面 發送廣播是一種實現方式外,還可以通過 android 的系統API RemoteCallbackList,用包名作為key值來注冊遠程回調介面的方式,讓服務端持有客戶端的回調介面,服務端調用回調介面,客戶端在回調介面中實現主動斷開服務端 ,通過這種方式變數地實現服務端主動斷開客戶端的功能。而採用後者會顯得更加優雅
既然所有的操作歸根結底都是由客戶端來完成的,那麼客戶端必須得有如下的功能模塊:
服務端必須得有的功能模塊:
那麼,整體的通信流程就是如下的步驟:
首先是通信的 aidl 介面定義
然後是客戶端的連接操作與斷開連接操作,包括廣播接收者的注冊以及回調介面的實現
然後是客戶端的拉取數據和推送數據操作
接著是服務端的 iBinder 介面的實現,完成回調介面的注冊、業務子線程的開啟和關閉、數據的推送和數據的拉取操作
然後是服務端的主動連接和主動斷開連接操作
最後是服務端的 onUnbind 方法的實現,對回調介面進行反注冊
服務端模仿 FloatViewPlugin 自定義插件,實現 IServicePlugin 介面,定製個性化的懸浮窗插件
客戶端在 Appliaction 的 onCreate方法中初始化
在 MainActivity 上實現連接、斷開、數據通信
C. android開發aidl何時使用
1.什麼是aidl:aidl是 Android Interface definition language的縮寫,一看就明白,它是一種android內部進程通信介面的描述語言,通過它我們可以定義進程間的通信介面
icp:interprocess communication :內部進程通信
2.既然aidl可以定義並實現進程通信,那麼我們怎麼使用它呢?文檔/android-sdk/docs/guide/developing/tools/aidl.html中對步驟作了詳細描述:
--1.Create your .aidl file - This file defines an interface (YourInterface.aidl) that defines the methods and fields available to a client.
創建你的aidl文件,我在後面給出了一個例子,它的aidl文件定義如下:寫法跟java代碼類似,但是這里有一點值得注意的就是它可以引用其它aidl文件中定義的介面,但是不能夠引用你的java類文件中定義的介面
package com.cao.android.demos.binder.aidl;
import com.cao.android.demos.binder.aidl.AIDLActivity;
interface AIDLService {
void registerTestCall(AIDLActivity cb);
void invokCallBack();
}
--2.Add the .aidl file to your makefile - (the ADT Plugin for Eclipse manages this for you). Android includes the compiler, called AIDL, in the tools/ directory.
編譯你的aidl文件,這個只要是在eclipse中開發,你的adt插件會像資源文件一樣把aidl文件編譯成java代碼生成在gen文件夾下,不用手動去編譯:編譯生成AIDLService.java如我例子中代碼
--3.Implement your interface methods - The AIDL compiler creates an interface in the Java programming language from your AIDL interface. This interface has an inner abstract class named Stub that inherits the interface (and implements a few additional methods necessary for the IPC call). You must create a class that extends YourInterface.Stub and implements the methods you declared in your .aidl file.
實現你定義aidl介面中的內部抽象類Stub,public static abstract class Stub extends android.os.Binder implements com.cao.android.demos.binder.aidl.AIDLService
Stub類繼承了Binder,並繼承我們在aidl文件中定義的介面,我們需要實現介面方法,下面是我在例子中實現的Stub類:
private final AIDLService.Stub mBinder = new AIDLService.Stub() {
@Override
public void invokCallBack() throws RemoteException {
Log("AIDLService.invokCallBack");
Rect1 rect = new Rect1();
rect.bottom=-1;
rect.left=-1;
rect.right=1;
rect.top=1;
callback.performAction(rect);
}
@Override
public void registerTestCall(AIDLActivity cb) throws RemoteException {
Log("AIDLService.registerTestCall");
callback = cb;
}
};
Stub翻譯成中文是存根的意思,注意Stub對象是在被調用端進程,也就是服務端進程,至此,服務端aidl服務端得編碼完成了。
--4.Expose your interface to clients - If you're writing a service, you should extend Service and override Service.onBind(Intent) to return an instance of your class that implements your interface.
第四步告訴你怎麼在客戶端如何調用服務端得aidl描述的介面對象,doc只告訴我們需要實現Service.onBind(Intent)方法,該方法會返回一個IBinder對象到客戶端,綁定服務時不是需要一個ServiceConnection對象么,在沒有了解aidl用法前一直不知道它是什麼作用,其實他就是用來在客戶端綁定service時接收service返回的IBinder對象的:
AIDLService mService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
Log("connect service");
mService = AIDLService.Stub.asInterface(service);
try {
mService.registerTestCall(mCallback);
} catch (RemoteException e) {
}
}
public void onServiceDisconnected(ComponentName className) {
Log("disconnect service");
mService = null;
}
};
mService就是AIDLService對象,具體可以看我後面提供的示例代碼,需要注意在客戶端需要存一個服務端實現了的aidl介面描述文件,但是客戶端只是使用該aidl介面,不需要實現它的Stub類,獲取服務端得aidl對象後mService = AIDLService.Stub.asInterface(service);,就可以在客戶端使用它了,對mService對象方法的調用不是在客戶端執行,而是在服務端執行。
4.aidl中使用java類,需要實現Parcelable介面,並且在定義類相同包下面對類進行聲明:
上面我定義了Rect1類
之後你就可以在aidl介面中對該類進行使用了
package com.cao.android.demos.binder.aidl;
import com.cao.android.demos.binder.aidl.Rect1;
interface AIDLActivity {
void performAction(in Rect1 rect);
}
注意in/out的說明,我這里使用了in表示輸入參數,out沒有試過,為什麼使用in/out暫時沒有做深入研究。
轉載
D. android之AIDL介紹
AIDL是一個縮寫,全稱是Android Interface Definition Language,也就是Android介面定義語言。
可以看出,AIDL是一種語言。
設計AIDL這門語言的目的是為了實現進程間通信,尤其是在涉及多進程並發情況下的進程間通信。
每一個進程都有自己的Dalvik VM實例,都有自己的一塊獨立的內存,都在自己的內存上存儲自己的數據,執行著自己的操作,都在自己的那片狹小的空間里過完自己的一生。
每個進程之間都你不知我,我不知你,就像是隔江相望的兩座小島一樣,都在同一個世界裡,但又各自有著自己的世界。
而AIDL,就是兩座小島之間溝通的橋梁。
我們可以通過AIDL來制定一些規則,規定它們能進行哪些交流——比如,它們可以在我們制定的規則下傳輸一些特定規格的數據。
通過這門語言,可以愉快的在一個進程訪問另一個進程的數據,甚至調用它的一些方法,當然,只能是特定的方法。
默認支持的數據類型包括:
AIDL實例文件:
E. android怎麼寫aidl文件
建立AIDL服務要比建立普通的服務復雜一些,具體步驟如下:
(1)在Eclipse Android工程的Java包目錄中建立一個擴展名為aidl的文件。該文件的語法類似於Java代碼,但會稍有不同。詳細介紹見實例52的內容。
(2)如果aidl文件的內容是正確的,ADT會自動生成一個Java介面文件(*.java)。
(3)建立一個服務類(Service的子類)。
(4)實現由aidl文件生成的Java介面。
(5)在AndroidManifest.xml文件中配置AIDL服務,尤其要注意的是,<action>標簽中android:name的屬性值就是客戶端要引用該服務的ID,也就是Intent類的參數值。
建立AIDL服務
本例中將建立一個簡單的AIDL服務。這個AIDL服務只有一個getValue方法,該方法返回一個String類型的值。在安裝完服務後,會在客戶端調用這個getValue方法,並將返回值在TextView組件中輸出。建立這個AIDL服務的步驟如下:
(1)建立一個aidl文件。在Java包目錄中建立一個IMyService.aidl文件。IMyService.aidl文件的位置如圖
IMyService.aidl文件的內容如下:
Java代碼:
package eoe.demo;
interface IMyService {
String getValue();
}
IMyService.aidl文件的內容與Java代碼非常相似,但要注意,不能加修飾符(例如,public、private)、AIDL服務不支持的數據類型(例如,InputStream、OutputStream)等內容。
(2)如果IMyService.aidl文件中的內容輸入正確,ADT會自動生成一個IMyService.java文件。讀者一般並不需要關心這個文件的具體內容,也不需要維護這個文件。關於該文件的具體內容,讀者可以查看本節提供的源代碼。
(3)編寫一個MyService類。MyService是Service的子類,在MyService類中定義了一個內嵌類(MyServiceImpl),該類是IMyService.Stub的子類。MyService類的代碼如下:
Java代碼:
package eoe.demo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class MyService extends Service {
public class MyServiceImpl extends IMyService.Stub {
@Override
public String getValue() throws RemoteException {
return "Android/OPhone開發講義";
}
}
@Override
public IBinder onBind(Intent intent) {
return new MyServiceImpl();
}
}
在編寫上面代碼時要注意如下兩點:
IMyService.Stub是根據IMyService.aidl文件自動生成的,一般並不需要管這個類的內容,只需要編寫一個繼承於IMyService.Stub類的子類(MyServiceImpl類)即可。
onBind方法必須返回MyServiceImpl類的對象實例,否則客戶端無法獲得服務對象。
(4)在AndroidManifest.xml文件中配置MyService類,代碼如下:
Java代碼:
<service android:name=".MyService" >
<intent-filter>
<action android:name="net.blogjava.mobile.aidl.IMyService" />
</intent-filter>
</service>
下面來編寫客戶端的調用代碼。首先新建一個Eclipse Android工程(ch08_aidlclient),並將自動生成的IMyService.java文件連同包目錄一起復制到ch08_aidlclient工程的src目錄中,如圖所示。
調用AIDL服務首先要綁定服務,然後才能獲得服務對象,代碼如下:
Java代碼:
package net.blogjava.mobile;
import net.blogjava.mobile.aidl.IMyService;
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.view.View; import android.view.View.OnClickListener;
import android.widget.Button; import android.widget.TextView;
public class Main extends Activity implements OnClickListener {
private IMyService myService = null;
private Button btnInvokeAIDLService;
private Button btnBindAIDLService;
private TextView textView;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 獲得服務對象
myService = IMyService.Stub.asInterface(service);
btnInvokeAIDLService.setEnabled(true);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnBindAIDLService:
// 綁定AIDL服務
bindService(new Intent("net.blogjava.mobile.aidl.IMyService"), serviceConnection, Context.BIND_AUTO_CREATE);
break;
case R.id.btnInvokeAIDLService:
try {
textView.setText(myService.getValue());
// 調用服務端的getValue方法
} catch (Exception e) {
}
break;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnInvokeAIDLService = (Button) findViewById(R.id.btnInvokeAIDLService);
btnBindAIDLService = (Button) findViewById(R.id.btnBindAIDLService); btnInvokeAIDLService.setEnabled(false);
textView = (TextView) findViewById(R.id.textview);
btnInvokeAIDLService.setOnClickListener(this);
btnBindAIDLService.setOnClickListener(this);
}。