在日常的代碼編寫中,Handler主要是用來進行線程間通信的一種手段,或者說一種工具來使用,一般我們都會將handler寫在主線程中,然後開啓一個Thread,在裏面進行post或者sendMessage,將Message從MessageQueue中送給Handler,然後我們獲取數據進行UI更新。
但是這是爲什麼呢?其實每一個Handler都會有一個MessageQueue,而MessageQueue是被封裝在Looper中的,而Looper又會關聯一個線程,最後就相當於一個MessageQueue關聯了線程,一個線程只有一個MessageQueue,一個Looper,之後在通過Message來打到線程間通信。
默認情況下,只有一個MessageQueue就是主線程會通過Looper.java中的prepareMainLooper()方法來創建出來,也就是Looper的生成時,會自動產生一個MessageQueue。
但是有一點要注意子線程默認情況下是沒有Looper的更不會有MessageQueue;
那麼Looper是怎麼創建的呢,Looper在主線程中,是通過prepareMainLooper()這個方法中的prepare()創建的源碼如下:
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { //如果looper的線程不唯一,拋出異常,looper已經在該線程被創建了
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed)); //否則,創建一個looper 並且綁定到創建Looper的線程
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
創建了MessageQueue之後,Looper就要綁定到創建Looper的線程,同時進行死循環,不斷傳遞MessageQueue中的Message給Handler,讓handler處理。
下面我們看一段部分源碼 這段源碼的主要功能就是死循環不斷傳遞MessageQueue中的Message給Handler
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); //MessageQueue是一個隊列結構 不斷地調用.next傳遞Message
if (msg == null) { //這裏可以看出Message是可以爲空的。
// No message indicates that the message queue is quitting.
return;
}
通常我們會認爲子線程是不能創建handler的,但是這是爲什麼呢,我們先開啓一個子線程,在裏面創建一個handler看看會發生什麼吧。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(){
Handler handler = null;
@Override
public void run() {
handler = new Handler();
}
}.start();
}
}
我們的程序崩潰了,同時拋出了Can't create handler inside thread that has not called Looper.prepare()的異常,這個異常的意思爲,我們不能在子線程創建hadnler,因爲無法調用Looper.prepare()方法,
所以我們無法使用Handler的原因就是Looper.prepare()是用來創建Looper的,因爲子線程默認不會產生Looper,所以也沒辦法產生MessageQueue,也不能發送Message來進行通信了,
解決辦法很簡單,只要我們手動執行Looper的prepare方法創建一個Looper,在執行prepare的時候,Looper會自動創建一個MessageQueue,並且綁定到Looper所在的線程,
然後通過調用loop方法,開啓無限循環就可以正常的在子線程執行Handler了代碼如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(){
Handler handler = null;
@Override
public void run() {
Looper.prepare(); //創建一個Looper,同時創建了MessageQueue,並且綁定了線程
handler = new Handler();
Looper.loop();//開啓Looper的循環
}
}.start();
}
}
總結:
1.子線程是可以創建Handler的,不能創建的原因是因爲子線程默認不會創建Looper,當Looper爲空就會拋出上述異常,導致程序崩潰掉。
2.Looper.prepare()方法會創建一個Looper對象,並且創建的同時通過
sThreadLocal.set(new Looper(quitAllowed));
這行代碼來爲創建的Looper綁定線程,同時Looper創建的同時會產生一個MessageQueue。
3.Looper.loop()方法會開啓死循環,不斷地遍歷MessageQueue。
4.解決辦法子線程不能創建Handler的方法 手動調用Looper.prepare()方法創建一個Looper並且調用Looper.loop()開啓循環就可以了。