2、AIDL中線程問題

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更新,我都可能會考慮使用工作線程。當然前提是做好線程同步。

 

 

 

 

 

 

 

 

發佈了65 篇原創文章 · 獲贊 28 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章