深入理解異步加載--Handler和Looper源碼解析(1)

這幾天由於比較空,仔細讀了下Handler,Looper,Message和MessageQueue的源代碼,再結合一些現有的資料(比如任玉剛的Android開發藝術探索),深入的理解了一下Android是如何進行線程切換,異步加載的。

在介紹之前,首先要對幾個主要類進行理解。

Looper類


Looper類比較簡單,主要只有2個操作
 public static void prepare() {
        prepare(true);
    }

    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的構造函數初始化Looper對象的,然後把looper對象賦值給ThreadLocal(這個類在下面會進行介紹)

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;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }
//這個方法就是類似自旋鎖的形式,用死循環的形式,去不停的取Message,只要取到Message就調用msg.target.dispatchMessage(msg);

Handler類

有幾個構造函數

//無參數的構造函數,主要調用Handler(Callback callback, boolean async)這個函數,在這個2個參數的構造函數裏詳細講下
public Handler() {
        this(null, false);
    }

public Handler(Callback callback) {
        this(callback, false);
    }
    //調用了public Handler(Looper looper, Callback callback, boolean async)
public Handler(Looper looper) {
        this(looper, null, false);
    }
public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }
 public Handler(boolean async) {
        this(null, async);
    }
//這裏的Callback是Handler裏的一個內部接口,如果外部類繼承了這個接口,可以把這個類作爲Handler的代理類,代替Handler去執行HandlerMessage的操作
然後 boolean async是用於判斷message每次send或者post的時候是否需要同步
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;
    }
public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

就用註釋主要講解下我們常用的幾個構造函數
我們一般在程序裏在主線程都使用 new Handler()的方式去獲得一個Handler的實例,因爲Looper.myLooper()得到的就是mainLooper。在子線程如果這麼調就會報錯
throw new RuntimeException(“No Looper; Looper.prepare() wasn’t called on this thread.”);
原來就是主線程會在線程啓動時調用prepareMainLooper()方法,去new 一個Looper的實例,但是子線程需要我們手動去實現一個Looper的實例
,需要調new Handler(Looper.getMainLooper())方法

然後Handler裏有幾個常用的方法

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

 public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

這2個方法的本質是一樣的都是調用了sendMessageDelayed方法
post(Runnable r)方法多執行了一步,就是把Runnable包裝成一個Message

private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

這裏會生成一個Message,然後把Runnable作爲一個成員變量的形式賦值給message,至於爲什麼這麼做,會在下面Handler如何處理Message中講到

然後我們再跟着代碼走,

 public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }


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);
    }

這裏看到sendMessageDelayed方法只是簡單的對delayMillis進行處理,如果小於0,就賦予0值。而sendMessageAtTime也只是對MessageQueue進行了非空判斷。最後把只是簡單的把message塞進了MessageQueue當中

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//這裏有一個我認爲比較聰明的做法,把Handler做爲一個target給Message,等Message取出來的時候,就能很輕鬆的獲得Handler的對象
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

這樣整個發送消息的過程就結束了
post/sendMessage->sendMessageDelayed->sendMessageAtTime->
enqueueMessage 主要流程就是把MessageQueue當中

然後再講下取的過程
Looper在取到Message後,會調用msg.target.dispatchMessage(msg)(就是上面說到Looper.loop()裏乾的事);
然後會調用

 /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
//這裏的msg.callback就是我們之前把Runbale賦值給Message時獲得的。
//如果你給msg設置了callback handlerMessage方法就會不執行, 如果遇到這個問題的同學就會明白爲什麼了
//然後會去判斷代理是否爲空,如果不爲空就讓代理去執行handlerMessage方法。
//只有上述2個條件都爲空纔會執行我們熟悉的HandlerMessage方法

這樣我們就能用Handler去執行我們之前在子線程希望UI線程乾的事情了,但是爲什麼這樣就切換到UI線程了,這個就跟ThreadLocal有關了和Looper有關了,會在下一章講明白

Message和MessageQueue在這就不多說,因爲代碼非常簡單,Message就是一個實體類和我們在平時定義的業務實體類一樣。
MessageQueue就是一個單向鏈表,插入和刪除消耗比較少。

發佈了37 篇原創文章 · 獲贊 77 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章