hello~,大家好,我叫石頭。
這幾天在重新梳理Android開發(fā)相關(guān)的知識點,今天在梳理hanlder的時候,突然感受是不是可以換一個角度來梳理handler的原理,這樣可能更有助于理解handler,接下來設(shè)計到的知識點有內(nèi)存, 線程,java內(nèi)存模型等相關(guān)概念。
假如我們一個引用的內(nèi)存有這些線程,handler,looper是不是有點暈乎乎的

下面我們就從另外一個角度切入,看看代碼究竟是怎么流轉(zhuǎn)的。
下面我會用大量的圖片展示handler在時間上內(nèi)存的變化模型(內(nèi)存只展示了相關(guān)的變量跟概念)
一個初始化的項目
當(dāng)我們新建一個項目,什么代碼都沒寫的時候,hanlder相關(guān)的內(nèi)存如下

這個時候我們有一個主線程(或者叫UI線程),這個時候系統(tǒng)會默認(rèn)幫我們綁定了一個looper對象
我們Activity的LifeCycler回調(diào)就是這個默認(rèn)looper來分發(fā)的。
Q:現(xiàn)在我們模擬一個場景就是:
界面元素: 1個Button, 1個TextView
任務(wù):點擊Button新開一個子線程,在里面執(zhí)行我們需要的一些耗時操作,之后通過主線程更新TextView
我們用偽代碼模擬下
第一步:創(chuàng)建Handler對象
Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 1:
// 處理UI更新
textView.setText("xxx");
break;
}
}
}
這里我們思考一下
handleMessage里面的代碼是在哪個線程里面執(zhí)行,如果我們把handler跟另外一個looper綁定,又會在哪個線程執(zhí)行handleMessage里面的代碼,后面我會給出答案.

第二步:添加Button點擊事件
點擊Button新開一個子線程,在里面執(zhí)行我們需要的一些耗時操作
Button button = findViewById(R.id.xxx);
button.setOnClickListener(v -> {
new Thread(() -> {
// 做一些耗時操作
doSomeWork();
});
});

第二步:在子線程中通過hander發(fā)送消息
Button button = findViewById(R.id.xxx);
button.setOnClickListener(v -> {
new Thread(() -> {
// 做一些耗時操作
doSomeWork();
Message msg = Message.obtain();
msg.what = 1; //消息的標(biāo)識
msg.obj = "子線程想發(fā)送給主線程的數(shù)據(jù)"; // 消息的存放
handler.sendMessage(msg);
});
});

這里主要想說明2點:
1.handler不是線程私有對象,所有能在子線程中通過其引用調(diào)用發(fā)送消息的方法.
2.looper是線程私有的,我們的消息最終會到達消息隊列(消息隊列在looper對象中)
在子線程通過handler引用調(diào)用sendMessage方法
第三步:在handler的handleMessage中處理消息

到這里我們的邏輯就完成了
但是我們要思考的是:
其實我們所謂的在子線程中發(fā)送消息消息,在主線程中處理消息,其實說白了都是在利用handler對象來處理的
因為handler沒有對象到線程中去,所以任何線程只要能拿到他的引用都能對其進行操作
- 子線程中發(fā)送消息消息:我們知道一個Thread類的
run方法是運行在子線程中的,所以在其中執(zhí)行handler.sendMessage(msg);方法也就是在子線程中。 - 主線程中處理消息: 我們知道
Message是被looper從MessageQueue取出,并且通過其中handler引用調(diào)用到了handleMessage中,looper是被主線程私有的,并且是在主線程中的run方法中輪詢處理的,所以這段代碼就是在主線程中執(zhí)行的.
總結(jié)一下就是
發(fā)送消息是在子線程的run方法進行的,處理消息是在主線程的run方法進行的,中間的邏輯紐帶是handler的引用。
所謂的一段代碼在哪個線程中運行,就是說的這段代碼的調(diào)用鏈?zhǔn)窃谀膫€線程的run中被調(diào)用的
進階思考
Q1: HandlerThread使用中的handler中的sendMessage是在哪個線程中?
Q2: HandlerThread使用中的handler中的handleMessage是在哪個線程中?
Q3: 怎么在子線程1中發(fā)送消息,在子線程2中處理消息?
Q4: 一個線程能有幾個looper,幾個handler(這個問法不太嚴(yán)謹(jǐn),想想為啥)?
