上一節咱們講解了Handler的基本使用方法,也是平時你們用到的最多的使用方式。那麼本節讓咱們來學習一下Handler的工做原理吧!!!android
咱們知道Android中咱們只能在ui線程(主線程)更新ui信息,那麼大家知道爲何只能經過Handler機制更新ui嗎?其實最根本的目的就是解決多線程併發的問題。面試
假設在一個Activity中有多個線程去更新ui,而且都沒有加鎖,那麼會是什麼樣子?多線程
致使的結果就是更新界面錯亂。併發
若是對更新ui的操做都進行加鎖處理的話又產生什麼問題哪?async
性能降低。ide
處於對以上問題的考慮,Android給咱們提供了一套更新ui的機制,咱們只須要遵照這樣的機制就能夠了。根本不用去關心多線程問題,由於全部更新ui的操做,都是在主線程的消息隊列當中經過輪訓處理的。oop
<一>Handler機制的角色和職責源碼分析
1 MessageQueue 消息隊列性能
存儲消息的容器,能夠向其中添加、取出消息。遵循先進先出的原則。學習
2 Handler
負責將消息發向消息容器即MessageQueue中。
3 Looper 輪訓器
經過調用自身的loop方法,不斷的從消息隊列當中取出消息併發送給target(即handler)處理消息。當消息隊列當中沒有輪訓消息時,它就處於堵塞狀態。
來個實際圖來看一下Handler的工做原理:
<二>Handler機制工做原理分析
Handler機制要想起做用有三個步驟:
1 建立Looper
2 建立Handler
3 調用Looper的loop方法,循環消息
下面讓咱們來看看android中,如何去遵循這三點的,在那以前,先普及一下一個知識:
默認整個應用程序,都是經過ActivityThread類啓動的,在ActivityThread類當中,負責建立咱們全部的Activity,並回調每一個Activity中的生命週期方法。在ActivityThread類中,默認會去建立一個線程,這個線程叫作main線程(主線程)。全部的應用程序,更新ui的操做,都是在這個main線程中進行的。
建立Looper和調用loop方法的工做,Android SDK 已經爲咱們作好了,因此咱們在平時使用的時候,只須要建立Handler併發送消息便可。下面咱們跟隨Android源碼看看它是怎麼作的。入口是ActivityThread的main方法。
跟進Looper的prepareMainLooper方法
跟進prepare方法
這裏咱們須要對ThreadLocal類進行一下解釋,ThreadLocal在咱們的線程當中用於去保存一些變量信息,默認狀況下,建立一個與線程相關的一個對象,是經過threadLocal存儲的,threadLocal有set和get方法,set是把變量設置到threadLocal當中 ,get方法是獲取出來。由於當前線程是ui線程,默認狀況下threadLocal是沒有存儲的,因此爲null,因此不走if而是new Looper對象以後在存儲,下面咱們在看看初始化Looper的時候作了哪些事情!
咱們看到,在建立Looper輪訓器的時候,自動的建立了消息隊列MessageQuene。也就是說默認的狀況下,android爲咱們自動建立了主線程的Looper和MessageQuene。
那麼Handler怎麼和咱們的MessageQuene消息隊列聯繫在一塊兒的那?由於以前不是說handler發出的消息是發送到消息隊列中了嗎?
緣由還要看咱們在建立Handler的時候作了那些事情,跟進Handler初始化源碼發現最終調用的是下面這個構造器建立實例的。
public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
跟進Looper的myLooper方法
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
看到了什麼?sThreadLocal是否是很熟悉,沒錯它就是ThreadLocal對象。默認狀況下android爲咱們建立了主線程Looper對象並存儲在sThreadLocal中,因此此處返回的就是主線程的Looper對象,也就是說咱們在建立Handler的時候,它就和消息隊列關聯起來了。
那麼當咱們使用handler發送消息的時候,無論使用哪種方法,一步一步跟進源碼發現最終調用的都是Handler的sendMessageAtTime方法
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }
看代碼可知,在發送消息的時候消息隊列不能爲null,繼續跟進enqueueMessage方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
能夠看到,消息最終發送到了消息隊列當中。那麼消息是怎麼輪訓的那?前面已經提過,是經過Looper的loop方法,那麼來看看吧!!!
能夠看到loop方法裏面的機制就是一個死循環,不斷的從消息隊列中取出消息,而後發送給target(handler對象)的dispatchMessage方法,跟進去!!!
通常狀況下咱們發送消息的時候沒有給Message的callback賦值,因此第一個if條件不知足。下面的mCallback是在咱們初始化Handler的時候才被初始化,Handler初始化有一種方法Handler(Callback callback),此處的參數就是給mCallback賦值的。咱們通常初始化Handler的時候使用的是空參數的構造器,因此致使mCallback未被初始化,因此會直接走handleMessage(msg)方法,也就是咱們初始化Handler時重寫的handleMessage方法。至此,Handler工做的機制就開始工做了,你、瞭解了嗎?
下面讓咱們看看若是咱們選擇的是帶Callback參數的初始化方式邏輯又會是什麼樣那,請看初始化代碼:
Handler mHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { Log.d(TAG,"callback參數-------handleMessage"); return true;//此處的返回值會影響下面的handleMessage方法是否調用 //false 調用 //true 不調用 } }){ @Override public void handleMessage(Message msg) { Log.d(TAG,"重寫handler的-------handleMessage方法"); super.handleMessage(msg); } };
根據上面的源碼分析咱們知道此處Callback參數中的handleMessage方法的返回值會影響到下面第二個handleMessage方法是否調用。通過驗證,return true 則不調用 ,return false則調用。
最會經過一張圖,看一下Handler的原理:
更形象一點,能夠看下圖:
好了,Android中的Handler機制工做原理我已經介紹完畢!!!參考了幕課網中《Android面試常客Handler詳解》,你們若是沒有明白能夠去該網站自行學習。下篇我將介紹如何在子線程建立Handler。