Handler系列之原理分析

  上一節咱們講解了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。

相關文章
相關標籤/搜索