AIDL在谷歌官方描述中推薦在 不同應用、多併發任務時使用。
在上一篇的基礎上,做一些打印和修改。
主要修改:getName方法爲耗時方法。即爲 getName方法增加 Thread.sleep(20000);
操作演示
1、修改getName爲耗時
2、打印客戶端代碼
點擊TextView,開始進行AIDL連接,在 onServiceConnected 中 使用耗時方法 getName,然後打印。
Button按鈕用於觸發ANR。爲什麼要用個Button去觸發ANR,因爲ANR是說APP無響應,是對某一事件無響應,如果你不去主動觸發Button 的 onClick方法,那麼這個不彈出ANR異常。
那麼我們看點擊後的效果。
3、點擊AIDL連接,查看客戶端打印信息
並沒有彈出ANR,因爲我點擊 “連接AIDL” 按鈕後,啥也沒做,所以不會觸發ANR
我們看客戶端打印信息
01-14 17:02:43.553 26563-26563/com.example.yanlong.aidlclient I/客戶端: bindAidl() 函數前一行
01-14 17:02:43.553 26563-26563/com.example.yanlong.aidlclient I/客戶端: bindAidl() 函數後一行
01-14 17:02:43.553 26563-26563/com.example.yanlong.aidlclient I/客戶端: onServiceConnected 中線程名稱main
01-14 17:02:43.553 26563-26563/com.example.yanlong.aidlclient I/客戶端: onServiceConnected 中獲取到 iUserAidlInterface 對象
01-14 17:03:03.553 26563-26563/com.example.yanlong.aidlclient I/客戶端: 您好,我的名字叫服務端
可以看到 最後三行。 主線程、獲取對象、調用函數。
在主線程中運行,獲取對象和調用函數相差20秒。
這時候我們看服務端打印的信息。
01-14 17:02:43.553 24759-24770/com.example.yanlong.aidlservice I/服務端: Binder_1
服務端當前線程名稱爲 binder_1 ,是個工作線程。這也正好符合了AIDL的 多併發使用。
既然是 binder_1 可以推測可能會有 binder_2 binder_3 等等一系列。
4、我們點一下 Button 會怎麼樣?
肯定ANR,不貼圖了。
如何修改
1、使用子線程去操作耗時請求
兩種思路,
①:當 OnClick後,使用工作線程運行其內部的bindAidl();函數。
②:當 準備調用 getName(); 函數時,開啓工作線程。
真相如何?答案只有一個,就是 只使用 ② 或 ①+② 使用。
我們看一下打印結果
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "bindAidl() 函數前一行");
new Thread(new Runnable() {
@Override
public void run() {
bindAidl();
}
},"自定義線程").start();
Log.i(TAG, "bindAidl() 函數後一行");
}
});
打印結果如下:
01-14 17:48:48.998 14017-14017/com.example.yanlong.aidlclient I/客戶端: bindAidl() 函數前一行
01-14 17:48:48.998 14017-14017/com.example.yanlong.aidlclient I/客戶端: bindAidl() 函數後一行
01-14 17:48:48.998 14017-14017/com.example.yanlong.aidlclient I/客戶端: onServiceConnected 中線程名稱main
01-14 17:48:48.998 14017-14017/com.example.yanlong.aidlclient I/客戶端: onServiceConnected 中獲取到 iUserAidlInterface 對象
01-14 17:49:08.998 14017-14017/com.example.yanlong.aidlclient I/客戶端: 您好,我的名字叫服務端
可以明顯看出,即使我們使用子線程去進行AIDL連接,
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "onServiceConnected 中線程名稱" + Thread.currentThread().getName());
IUserAidlInterface iUserAidlInterface = IUserAidlInterface.Stub.asInterface(service);
Log.i(TAG, "onServiceConnected 中獲取到 iUserAidlInterface 對象");
try {
String name1 = iUserAidlInterface.getName();
Log.i(TAG, name1);
} catch (RemoteException e) {
e.printStackTrace();
}
}
onServiceConnected的回調依然是主線程,所以這裏建議可以用子線程去開啓 AIDL連接,但是一定要在調用遠程耗時方法處使用工作線程。
其實從我角度出發來說,只要不涉及到UI更新,我都可能會考慮使用工作線程。當然前提是做好線程同步。