Handler機制是面試中的常客了,今天和你們一塊兒經過源碼層面來解析一下。
@[toc]java
Handler機制涉及到幾個類: MessageQueue, Looper, Message, ActivityThread。面試
AppCompatActivity.java-> FragmentActivity.java->SupportActivity.java->Activity.javaapp
在Activity中默認有一個ActivityThread這是一個main thread,其中final Looper mLooper = Looper.myLooper();實例化了一個looper對象。
在ActivityThread.java中的main方法中,有以下代碼ide
public static void main(String[] args) { ...省略其餘代碼 Looper.prepareMainLooper(); ...省略其餘代碼 Looper.loop(); }
Looper.java public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); } // Looper構造函數中初始了消息隊列MessageQueue對象 private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
建立looper 對象以前,會判斷 sThreaLocal 中是否已經綁定過 Looper 對象,若是是則拋出異常,確保一個線程中Looper.prepare()只調用一次。
若是在MainActivity中調用,以下代碼,會報錯。
函數
經過上述代碼能夠得知,Activity中默認開始了loop()循環,用於獲取handler發送的消息。oop
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private final String TAG = "MainActivity"; public final int MSG_DOWN_FAIL = 1; public final int MSG_DOWN_SUCCESS = 2; public final int MSG_DOWN_START = 3; @BindView(R.id.btn_start_thread) Button btnStart; @BindView(R.id.tv_status) TextView tvShow; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_DOWN_START: tvShow.setText("down start"); break; case MSG_DOWN_SUCCESS: tvShow.setText("down success"); break; case MSG_DOWN_FAIL: tvShow.setText("down fail"); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); btnStart.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_start_thread: new MyThread().start(); break; default: break; } } class MyThread extends Thread { @Override public void run() { handler.sendEmptyMessage(MSG_DOWN_START); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } Message msg = Message.obtain(); msg.what = MSG_DOWN_SUCCESS; handler.sendMessage(msg); } } }
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }
sendMessage調用了sendMessageDelayed->sendMessageAtTime->enqueueMessage, 最終調用了MessageQueue的enqueueMessage的方法, 並將本身設置爲message的targetpost
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
接下來就到了消息隊列MessageQueue中了,來看一下ui
其實這裏就是Looper.loop()方法從消息隊列中不斷循環取消息了。
不斷調用MessageQueue的next()方法取消息,若是message不爲null, 則調用handler的dispatchMessage分發消息。
這個handleMessage方法就是在建立Handler中覆蓋的方法。this
至此 Handler 的發送消息和消息處理流程已經介紹完畢。spa
Android的Ui線程,開啓了一個死循環,可是並無阻塞主線程是爲何呢?
在MessageQueue的next方法中有這樣一行代碼
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
nativePollOnce 方法是一個 native 方法,當調用此 native 方法時,主線程會釋放 CPU 資源進入休眠狀態,直到下條消息到達或者有事務發生,經過往 pipe 管道寫端寫入數據來喚醒主線程工做,這裏採用的 epoll 機制。
messageQueue的enqueueMessage是按照消息的when時間有序加入到隊列的,取的時候也是按照時間進行取的
能夠看到若是當前時間小於msg設置的時間,會計算一個timeout,在timeout到了以後,纔會將UI線程喚醒,交由CPU執行。
1.APP啓動建立主線程的時候會經過ActivityThread執行Looper.prepare(),建立一個looper 對象,在私有的構造方法中又建立了 MessageQueue 做爲此 Looper 對象的成員變量,Looper 對象經過 ThreadLocal 綁定 MainThread 中。2.在建立Handler對象的時候,經過構造函數獲取ThreadLocal 綁定的looper對象,並經過looper獲取消息隊列MessageQueue做爲成員變量3.子線程發送消息時,將msg的target設置爲handler自身,以後調用成員MessageQueue的enqueueMessage將消息按照msg.when時間排序插入到消息隊列4.主線程經過Looper.loop()開啓不阻塞UI線程的死循環,經過綁定的looper對象獲取MessageQueue,調用next()方法不斷獲取msg, 並經過(handler)msg.target.dispatchMessage發送至咱們建立的handler時覆蓋的handleMessage()方法