Android-Handler源碼

一侮措、什么是Handler

1.Android SDK中用來(lái)處理異步消息的核心類
2.子線程可以通過(guò)Handler來(lái)通知主線程進(jìn)行UI更新

二、Handler機(jī)制的核心類

Handler:mLooper,mQueue(mLooper是從Looper中的ThreadLocal對(duì)象中獲取的泽谨,整個(gè)app中碧囊,所有的Looper對(duì)象都是保存在Looper類中的ThreadLocal靜態(tài)對(duì)象中,mQueue是根據(jù)mLooper中的mQueue賦值的)
Message
Looper:mQueue(是一個(gè)MessageQueue對(duì)象)
MessageQueue:采用單鏈表的方式存儲(chǔ)Handler需要處理的Message信息

Message:
在整個(gè)消息機(jī)制中供嚎,Message又叫Task黄娘,封裝了任務(wù)攜帶的信息和處理該任務(wù)的Handler:
1.盡管Message有public默認(rèn)的構(gòu)造方法,但是應(yīng)該通過(guò)Message.obtain()來(lái)從消息池中獲取空消息對(duì)象克滴,以節(jié)省資源逼争。
2.Message如果只需要攜帶簡(jiǎn)單的int信息,請(qǐng)優(yōu)先使用arg1和arg2來(lái)傳遞消息劝赔,這比使用Bundle更節(jié)省內(nèi)存誓焦。

Looper:輪循器
在Looper內(nèi)部有一個(gè)Thread對(duì)象,存放Looper對(duì)應(yīng)的當(dāng)前線程對(duì)象着帽。Looper內(nèi)部有一個(gè)MessageQueue隊(duì)列杂伟。用來(lái)存放消息移层。Looper輪循的時(shí)候,都是從當(dāng)前線程的Looper對(duì)象中取出MessageQueue赫粥,而當(dāng)前線程的Looper對(duì)象從ThreadLocal中獲得观话。而ThreadLocal對(duì)象則是在Looper中的一個(gè)靜態(tài)對(duì)象,是一個(gè)全局的越平。

三频蛔、原理分析

1.Looper實(shí)例創(chuàng)建和保存原理分析

MessageQueue 就是設(shè)計(jì)模式中的緩沖區(qū),它負(fù)責(zé)接收生產(chǎn)者發(fā)送過(guò)來(lái)的數(shù)據(jù)先進(jìn)先出的隊(duì)列形式秦叛,保存著所有消息晦溪。在UI Thread中通過(guò)looper 不斷從MessageQueue 取出消息在執(zhí)行任務(wù)。

Handler中獲取Looper對(duì)象:
public Handler(Callback callback, boolean async) {
   //省略一些無(wú)關(guān)代碼
    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 static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

在Android中书闸,所有的Looper對(duì)象都是保存在一個(gè)全局的ThreadLocal對(duì)象中尼变,Handler在線程中獲取Looper對(duì)象的時(shí)候,是調(diào)用ThreadLocal的get方法浆劲,ThreadLocal的get方法中嫌术,會(huì)優(yōu)先獲取當(dāng)前線程對(duì)象。

ThreadLocal的get方法的實(shí)現(xiàn):
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);//this是ThreadLocal<Looper>對(duì)象
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;//value即為L(zhǎng)ooper對(duì)象
            return result;
        }
    }
    return setInitialValue();
}
    //ThreadLocal的getMap的源碼:
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

其實(shí)每個(gè)Thread線程中都會(huì)有一個(gè)ThreadLocalMap對(duì)象牌借。每個(gè)線程對(duì)應(yīng)的Looper實(shí)例度气,其實(shí)就是保存在每個(gè)線程實(shí)例中的ThreadLocalMap實(shí)例中

Looper 的主要工作就是維護(hù)MessageQueque中的消息隊(duì)列,它負(fù)責(zé)從MessageQueue中取出要執(zhí)行的消息任務(wù)膨报,先判斷Looper是否為null磷籍,不為null就循環(huán)狀態(tài)不斷從MessageQueue中取出消息,然后通過(guò)dispatchMessage派發(fā)出去就行處理现柠。

看下Looper的創(chuàng)建過(guò)程:
public static void loop() {
    // 調(diào)用Looper.myLooper()方法院领,從ThreadLocal中取出當(dāng)前線程的Looper對(duì)象
    final Looper me = myLooper();
    // 如果當(dāng)前線程中的Looper對(duì)象為null,則會(huì)拋出異常
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;
    .....
    for (;;) {
        // 通過(guò)一個(gè)死循環(huán)够吩,從MessageQueue中不停的取出消息
        Message msg = queue.next(); // might block
            if (msg == null) {
                // 由于剛創(chuàng)建的MessageQueue就開(kāi)始輪詢比然,隊(duì)列里沒(méi)有消息
                // 等到Handler調(diào)用send或者post發(fā)送消息,進(jìn)而調(diào)用MessageQueue.enqueueMessage后
                // 隊(duì)列里才有消息
                return;
            }
            ........
            try {
               // 分發(fā)信息周循,target是一個(gè)Handler對(duì)象强法,這里就是調(diào)用Handler來(lái)分發(fā)信息的。
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            .........
            msg.recycleUnchecked();
        }
    }

每個(gè)線程只能有一個(gè)Looper對(duì)象湾笛,而且是通過(guò)ThreadLocal來(lái)存放饮怯,其他線程無(wú)法訪問(wèn)當(dāng)前的Looper。

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

Looper可以讓一個(gè)普通線程具有消息循環(huán)的能力,這是源碼給出的一段示例嚎研。

class LooperThread extends Thread {
     public Handler mHandler;

     public void run() {
         Looper.prepare();

         mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };

        Looper.loop();
     }

每個(gè)application都默認(rèn)擁有一個(gè)Looper對(duì)象注釋可以看到蓖墅。在啟動(dòng)應(yīng)用程序進(jìn)程過(guò)程中,會(huì)在最后調(diào)用ActivityThread.main方法,在ActivityThread.main方法中會(huì)調(diào)用Looper.prepareMainLooper()方法初始化主線程的Looper實(shí)例置媳,所以說(shuō)UI線程默認(rèn)就有一個(gè)Looper對(duì)象于樟,可通過(guò)Looper.myLooper()方法獲取到公条。因?yàn)長(zhǎng)ooper中用來(lái)保存Looper實(shí)例的ThreadLocal是一個(gè)靜態(tài)常量拇囊,內(nèi)存中只有這一個(gè)。又根據(jù)ThreadLocal的set和get的特性靶橱,所以可以根據(jù)不同的線程取出不同的值

    /**
     * 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() {
        // 這里傳入false寥袭,代表MessageQueue是不允許退出的
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    /**
     * Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

常用的方法 prepare()創(chuàng)建一個(gè)looper對(duì)象,在其他線程中想具有消息循環(huán)功能這個(gè)方法就必須調(diào)用关霸。
在Looper.prepare()方法中传黄,調(diào)用了重載方法參數(shù)傳的是true,表示是允許退出队寇,在創(chuàng)建Looper對(duì)象的時(shí)候膘掰,會(huì)將Looper所屬的當(dāng)前線程是哪個(gè)緩存在Looper實(shí)例中

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

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

在Looper實(shí)例中,通過(guò)調(diào)用其loop()方法佳遣,開(kāi)始循環(huán)取出消息

public static void loop() {}

2.Handler的消息發(fā)送和處理過(guò)程分析

Handler 是負(fù)責(zé)把Message壓入Queue中识埋,還負(fù)責(zé)處理Message。Handler工作必須依賴Looper才行零渐,沒(méi)有Looper對(duì)象會(huì)拋出RuntimeException異常窒舟,不管是post sendMessage 還是延時(shí)的消息發(fā)送,最終都會(huì)到enqueueMessage方法中把消息傳到緩沖區(qū)等待Looper處理诵盼。

創(chuàng)建Handler
    public Handler(@Nullable 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());
            }
        }
        // 獲取當(dāng)前線程中的Looper實(shí)例
        mLooper = Looper.myLooper();
        // 如果當(dāng)前線程中的Looper對(duì)象為null惠豺,則拋出異常,從這里可以看出創(chuàng)建Handler對(duì)象
        // 當(dāng)前線程就必須要先有Looper對(duì)象
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        // 每個(gè)Handler中使用的MessageQueue對(duì)象风宁,都是從Looper對(duì)象中取出的
        // 一個(gè)線程只有一個(gè)Looper對(duì)象洁墙,可以有多少Handler對(duì)象
        // 所以一個(gè)線程中的多個(gè)Handler對(duì)象是共用一個(gè)MessageQueue的
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
創(chuàng)建Message

可以直接new Message,但是有更好的方式Message.obtain戒财。因?yàn)榭梢詸z查是否可以有復(fù)用的Message用過(guò)復(fù)用避免過(guò)多的創(chuàng)建热监,銷(xiāo)毀Message對(duì)象達(dá)到優(yōu)化內(nèi)存和性能的目的

    public static Message obtain(Handler h) {
        // 調(diào)用重載的obtain方法
        Message m = obtain();
        // 并綁定創(chuàng)建Message對(duì)象的Handler對(duì)象
        m.target = h;

        return m;
    }
    public static Message obtain() {
        // sPoolSync是一個(gè)Object對(duì)象,用來(lái)同步保證線程安全的
        synchronized (sPoolSync) {
            // sPool其實(shí)就是Handler.dispatchMessage后通過(guò)recycleUnchecked回收用以復(fù)用的Message
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
Handler內(nèi)部發(fā)送消息方法源碼解析:

(1)sendMessage方法固翰,內(nèi)部調(diào)用的是sendMessageDelayed狼纬,只不過(guò)時(shí)間傳0

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

(2)sendMessageDelayed

    public final boolean sendMessageDelayed(Message msg, long delayMillis){
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    //SystemClock.uptimeMillis()表示從開(kāi)機(jī)到現(xiàn)在的毫秒數(shù)
    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);
    }
    // 將Message與發(fā)送Message的Handler做綁定
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// 這部分,是對(duì)Message進(jìn)行賦值骂际,將當(dāng)前的Handler對(duì)象賦值給Message.target
// 但是如果Message是采用obtain方法創(chuàng)建的疗琉,則在這個(gè)方法內(nèi)部會(huì)對(duì)target賦值
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

在Handler的enqueueMessage方法中可以看出,每個(gè)Message實(shí)例歉铝,在這里會(huì)對(duì)其target賦值Handler實(shí)例盈简,賦值的目的就是為了在Looper.loop()方法調(diào)用的時(shí)候用來(lái)在Looper.loop()方法中取出消息并且通過(guò)消息的target來(lái)將消息分發(fā)給對(duì)應(yīng)的Handler。這里的Handler是在發(fā)送消息的時(shí)候,將Message與Handler先做個(gè)綁定柠贤,即將Handler實(shí)例保存在Message中的target屬性中
注意:

System.currentTimeMillis()獲取的時(shí)間香浩,可以通過(guò)System.setCurrentTimeMillis(long)方法,進(jìn)行修改臼勉,那么在某些情況下邻吭,一旦被修改,時(shí)間間隔就不準(zhǔn)了宴霸,所以推薦使用SystemClock.uptimeMillis()囱晴,這樣就可以保證消息隊(duì)列中每個(gè)消息的時(shí)間順序是準(zhǔn)確的

MessageQueue內(nèi)部消息入隊(duì)處理

而MessageQueue的enqueueMessage,就是將消息入隊(duì)的操作瓢谢,MessageQueue是單向鏈表結(jié)構(gòu)畸写,是采用先入先出的操作來(lái)處理消息

    boolean enqueueMessage(Message msg, long when) {
// 判斷消息是否為空
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
// 判斷消息是否正在使用
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

// 采用同步方法塊的方式,實(shí)現(xiàn)線程同步氓扛,保證一個(gè)隊(duì)列一次只處理一個(gè)消息的入隊(duì)
        synchronized (this) {
// 判斷Looper是否有退出枯芬,這是在Looper.quit()方法中調(diào)用mQueue.quit(false);設(shè)置mQuitting為true的
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
// 回收消息,但是如果消息正在使用采郎,則會(huì)拋異常千所,不會(huì)回收
                msg.recycle();
                return false;
            }
// 設(shè)置消息為正在使用
            msg.markInUse();
// 獲取當(dāng)前時(shí)間
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
// p相當(dāng)于當(dāng)前Message的head
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
// 采用無(wú)限for循環(huán)尋找插入點(diǎn),直到找到為null的時(shí)候尉剩,因?yàn)檫@個(gè)時(shí)候p為當(dāng)前節(jié)點(diǎn)真慢,而prev為前一個(gè)節(jié)點(diǎn),找到為空的當(dāng)前節(jié)點(diǎn)理茎,然后在這個(gè)位置插入
            // for循環(huán)遍歷Message隊(duì)列黑界,如果當(dāng)前要插入的msg的時(shí)間
            // 大于當(dāng)前遍歷到的Message隊(duì)列中的節(jié)點(diǎn)的時(shí)間
            // 則繼續(xù)遍歷,如果當(dāng)前要插入的msg的時(shí)間when小于當(dāng)前遍歷到
            // 的節(jié)點(diǎn)p的時(shí)間when皂林,則將消息插入到p節(jié)點(diǎn)之前
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                // 設(shè)置需要插入的Message的下一個(gè)節(jié)點(diǎn)為null
                // 設(shè)置前一個(gè)節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)為Message
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            // 這里是判斷線程是否需要被喚醒
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

這里的nativeWake朗鸠,其實(shí)是調(diào)用了frameworks/base/core/jni/android_os_MessageQueue.cpp中的

static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->wake();
}

而這里的NativeMessageQueue的wake()方法,其實(shí)就是在android_os_MessageQueue.cpp中實(shí)現(xiàn)的

void NativeMessageQueue::wake() {
    mLooper->wake();
}
Looper.loop()循環(huán)處理消息并分發(fā)

MessageQueue的出隊(duì)操作础倍,其實(shí)就是next()方法烛占,返回一個(gè)Message。在線程中沟启,創(chuàng)建Looper實(shí)例之后忆家,通過(guò)調(diào)用Looper.loop()方法,循環(huán)從每個(gè)Looper實(shí)例中對(duì)應(yīng)的MessageQueue消息緩存隊(duì)列中讀取消息德迹,并且分發(fā)給Handler處理

    Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
// 是否退出的判斷
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        // 無(wú)限for循環(huán)
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                // 因?yàn)橄乱粭lMessage尚未到處理時(shí)間芽卿,則會(huì)將等待過(guò)程中需要處理的內(nèi)容交給CPU
                Binder.flushPendingCommands();
            }
            // 這里會(huì)有一個(gè)等待,在這個(gè)等待中設(shè)置了一個(gè)超時(shí)時(shí)間胳搞,即postDelayed等方式發(fā)送的延遲處理的消息卸例,其實(shí)是通過(guò)等待一定的時(shí)間再繼續(xù)執(zhí)行的方式來(lái)進(jìn)行
            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
// 如果當(dāng)前的msg不為空称杨,但是這個(gè)msg中的Handler為空,那么直接拿下一個(gè)消息筷转,因?yàn)檫@個(gè)消息已經(jīng)沒(méi)有Handler來(lái)進(jìn)行處理
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    //判斷當(dāng)前時(shí)間是否小于下一條要處理的消息的時(shí)間
                    if (now < msg.when) {
                        // 下一條消息尚未就緒姑原。 設(shè)置超時(shí)以在準(zhǔn)備就緒時(shí)喚醒。
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        // 取出消息呜舒,如果前一個(gè)消息不為空锭汛,則將前一個(gè)消息的指向指到當(dāng)前消息的下一個(gè)
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            // 如果前一個(gè)消息為空,則說(shuō)明當(dāng)前消息是第一個(gè)
                            mMessages = msg.next;
                        }
                        // 將當(dāng)前消息的指向置為null
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

而在Looper的loop()輪循器中通過(guò)MessageQueue.next()方法取出消息

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

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

        for (;;) {
            // 調(diào)用MessageQueue的next()方法阴绢,取出下一次要處理的消息
            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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
                // 獲取到Message對(duì)象之后店乐,調(diào)用這個(gè)消息對(duì)象中所保存的Handler對(duì)象,
                //然后通過(guò)Handler的dispatchMessage方法分發(fā)消息
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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();
        }
    }

在調(diào)用Looper.loop()方法處理消息的時(shí)候呻袭,會(huì)通過(guò)Message中緩存的每個(gè)消息對(duì)應(yīng)的target(也就是對(duì)應(yīng)的Handler實(shí)例)來(lái)發(fā)送給對(duì)應(yīng)的Handler,因?yàn)樵诎l(fā)送消息的時(shí)候會(huì)設(shè)置消息的target

Handler的dispatchMessage方法:

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

而handleMessage就是我們?cè)谑褂肏andler的時(shí)候重寫(xiě)的那個(gè)方法

public void handleMessage(Message msg) {

}

在Handler的dispatchMessage方法中腺兴,如果實(shí)現(xiàn)了Handler的Callback接口左电,并且重寫(xiě)該接口的handleMessage方法,那么該方法一般需要返回為false页响,目的是為了執(zhí)行Handler類中的handleMessage方法篓足,如果不執(zhí)行Handler類中的handleMessage方法,則可以返回為true闰蚕,但是一般返回false

3.主線程創(chuàng)建Looper實(shí)例

在android應(yīng)用程序進(jìn)程啟動(dòng)過(guò)程中栈拖,由系統(tǒng)AMS向Zygote進(jìn)程發(fā)送啟動(dòng)應(yīng)用程序進(jìn)程的請(qǐng)求,然后在Zygote接收到該請(qǐng)求之后没陡,通過(guò)fock自身創(chuàng)建了應(yīng)用程序進(jìn)程涩哟,并且通過(guò)異常捕獲處理的方式捕獲ActivityThread.main方法,然后調(diào)用盼玄,在ActivityThread.main方法中贴彼,通過(guò)Looper.prepareMainLooper()創(chuàng)建主線程的Looper實(shí)例
Looper:
這是ActivityThread類:

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");
// 創(chuàng)建Activity的Looper對(duì)象
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 調(diào)用Looper循環(huán)
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

在創(chuàng)建主線程的Looper實(shí)例的時(shí)候,默認(rèn)的quitAllowed是傳了false埃儿,是不允許退出的器仗。因?yàn)閟MainLooper!=null的時(shí)候會(huì)拋出異常童番,說(shuō)明每個(gè)線程就只能有一個(gè)Looper對(duì)象精钮。

4.主線程為什么不會(huì)阻塞問(wèn)題

Looper.loop()中的for循環(huán)實(shí)際上是阻塞了整個(gè)Android检诗,而Android之所以不會(huì)阻塞劲赠,是因?yàn)锳ndroid是一個(gè)消息驅(qū)動(dòng)機(jī)制略板,在ActivityThread中有一個(gè)H類對(duì)象顷编,這個(gè)H類是Handler的子類何鸡,Android的所有事件都是通過(guò)H類接受到Message之后垢啼,然后通過(guò)Handler的handleMessage方法進(jìn)行消息處理的畴嘶。這個(gè)過(guò)程溶其,就是在ActivityThread中的main方法中會(huì)創(chuàng)建一個(gè)ActivityThread對(duì)象,然后通過(guò)ActivityThread.getHandler就可以獲得H對(duì)象策橘,也就是Handler對(duì)象炸渡,這個(gè)對(duì)象就是在ActivityThread中創(chuàng)建的一個(gè)常量對(duì)象。

5.Handler導(dǎo)致的內(nèi)存泄漏問(wèn)題

Handler導(dǎo)致內(nèi)存泄露的原因:
  • (1)因?yàn)槎x的匿名內(nèi)部類丽已,會(huì)持有外部類的引用this蚌堵,可以直接調(diào)用外部類的方法和屬性。
  • (2)生命周期的問(wèn)題沛婴。因?yàn)镠andler.sendMessageAtTime會(huì)調(diào)用enqueueMessage吼畏,然后msg.target=this,說(shuō)明Message會(huì)持有Handler嘁灯,而Message在傳遞過(guò)程中泻蚊,會(huì)有延時(shí)的情況,比如設(shè)置20s執(zhí)行丑婿、20分鐘執(zhí)行性雄,這樣就會(huì)出現(xiàn)Message持有了Handler,而Handler持有了Activity羹奉,但是當(dāng)Activity銷(xiāo)毀的時(shí)候秒旋,可能Message還沒(méi)處理,還在延遲等待诀拭,這樣就導(dǎo)致Activity根據(jù)JVM可達(dá)性分析算法得出Activity不能被GC回收迁筛。

下面這段代碼是一個(gè)內(nèi)部類,在Java中內(nèi)部類或者匿名內(nèi)部類都會(huì)隱私的持有外部類對(duì)象耕挨,而在Android中使用Handler的一般都是Activity细卧,這就導(dǎo)致如果handler還在執(zhí)行中而actiivty finsh掉,activity就不能被正常銷(xiāo)毀回收俗孝。進(jìn)而GC的時(shí)候就導(dǎo)致JVM不能回收Activity酒甸,有可能多次操作后就OOM了。

解決辦法:

(1)把內(nèi)部類換成static, static不會(huì)隱式持有外部對(duì)象赋铝。
由于Handler不再持有外部類對(duì)象的引用插勤,導(dǎo)致程序不允許你在Handler中操作Activity中的對(duì)象了。所以你需要在Handler中增加一個(gè)對(duì)Activity的弱引用

(2)一般Handler導(dǎo)致的內(nèi)存泄漏都是因?yàn)楦锕牵⑻幚硎钱惒降呐┘狻insh的時(shí)候消息還在處理等待狀態(tài),這個(gè)時(shí)候可以在activity finsh的時(shí)候把handler移除掉良哲,調(diào)用removeCallbacks方法移除盛卡。

(3)關(guān)閉Activity的時(shí)候停掉你的后臺(tái)線程。

如何避免在使用Handler的時(shí)候造成內(nèi)存泄漏呢筑凫?

使用顯形的引用滑沧,1.靜態(tài)內(nèi)部類并村。 2. 外部類
使用弱引用 2. WeakReference

兩者同時(shí)使用

    private static class MyHandler extends Handler {  
        private final WeakReference<HandlerActivity2> mActivity;  
  
        public MyHandler(HandlerActivity2 activity) {  
            mActivity = new WeakReference<HandlerActivity2>(activity);  
        }  
  
        @Override  
        public void handleMessage(Message msg) {  
            System.out.println(msg);  
            if (mActivity.get() == null) {  
                return;  
            }  
            mActivity.get().todo();  
        }  
    }  

使用弱引用,其實(shí)就是將對(duì)應(yīng)的Activity存在弱引用中滓技。
并且在Activity被finish的時(shí)候哩牍,還要清空MessageQueue中的正在排隊(duì)的消息。
在onDestroy中調(diào)用下面的方法清空
mHandler.removeCallbacksAndMessages(null);

Looper:
public void quit() {
    mQueue.quit(false);
}

MessageQueue:
void quit(boolean safe) {
    if (!mQuitAllowed) {
        throw new IllegalStateException("Main thread not allowed to quit.");
    }

    synchronized (this) {
        if (mQuitting) {
            return;
        }
        mQuitting = true;
        // 清除消息令漂,這樣消息隊(duì)列為null膝昆,就會(huì)進(jìn)入一個(gè)無(wú)限等待狀態(tài)
        if (safe) {
            removeAllFutureMessagesLocked();
        } else {
            removeAllMessagesLocked();
        }

        // 喚醒等待
        nativeWake(mPtr);
    }
}

6.子線程中維護(hù)的Looper,消息隊(duì)列無(wú)消息的時(shí)候處理方法是什么叠必?有什么用荚孵?

必須要調(diào)用Looper.quit()或者quitSafely(),會(huì)把mQuitting賦值為true纬朝,會(huì)把所有的消息全部清空收叶,然后調(diào)用nativeWake(mPtr),喚醒玄组。喚醒是因?yàn)榍蹇障⒌臅r(shí)候滔驾,消息隊(duì)列為null,而Looper.loop()方法依然會(huì)在循環(huán)取出消息俄讹,就會(huì)陷入一個(gè)無(wú)限等待狀態(tài),那么就需要喚醒绕德,在next()方法中退出無(wú)限死循環(huán)患膛,直接調(diào)用return null返回一個(gè)空的null,返回空的null的時(shí)候耻蛇,在Looper.loop()方法中就會(huì)結(jié)束踪蹬。
因?yàn)橄㈥?duì)列無(wú)消息的時(shí)候,主動(dòng)調(diào)用Looper.quit()臣咖,其實(shí)就會(huì)調(diào)用MessageQueue的quit方法跃捣。
MessageQueue.quit()

    void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            // 將正在退出的標(biāo)志置為true,這樣在MessageQueue.next取出消息的時(shí)候夺蛇,就可以將消息返回一個(gè)null
            // 而在Looper.loop()遍歷消息的時(shí)候疚漆,當(dāng)取出的消息為null的時(shí)候,就直接return
            mQuitting = true;
            // 清空消息隊(duì)列
            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }

            // 喚醒消息隊(duì)列刁赦,這樣做的目的是消息隊(duì)列為null的時(shí)候娶聘,MessageQueue是處于阻塞狀態(tài)
            // 而這里喚醒的目的就是為了在next方法中返回一個(gè)空消息給Looper.loop()進(jìn)行處理
            nativeWake(mPtr);
        }
    }

7.線程同步問(wèn)題

Handler機(jī)制中最主要的類MessageQueue,這個(gè)類是所有消息的存儲(chǔ)隊(duì)列甚脉,是采用優(yōu)先級(jí)隊(duì)列的方式存儲(chǔ)消息丸升,而MessageQueue類中主要的就是消息入隊(duì)和出隊(duì),分別是enqueueMessage和next方法牺氨,這兩個(gè)方法中狡耻,都是采用的synchronized關(guān)鍵字代碼塊的方式來(lái)保證消息同步的墩剖,傳入的鎖是this,即對(duì)象鎖夷狰,MessageQueue對(duì)象鎖岭皂,因?yàn)橐粋€(gè)線程對(duì)應(yīng)一個(gè)Looper,而一個(gè)Looper對(duì)應(yīng)一個(gè)MessageQueue孵淘,所以一個(gè)線程中不管多少個(gè)Handler發(fā)送和處理消息蒲障,最終都是通過(guò)synchronized同步代碼塊保證消息的入隊(duì)和出隊(duì)的同步,保證線程安全瘫证。這對(duì)于在調(diào)用同一個(gè)MessageQueue的handler對(duì)象來(lái)說(shuō)揉阎,他們是在同一個(gè)線程的,而在這個(gè)線程內(nèi)背捌,入隊(duì)和出隊(duì)都是互斥的毙籽。并且因?yàn)橐粋€(gè)線程只有一個(gè)Looper對(duì)象,一個(gè)Looper對(duì)象對(duì)應(yīng)一個(gè)MessageQueue毡庆,所以在一個(gè)線程內(nèi)坑赡,不管有多少個(gè)Handler對(duì)象一次都只會(huì)處理一個(gè)消息,因?yàn)樵贚ooper.loop()循環(huán)遍歷消息的時(shí)候么抗,每次就只能同步出去一個(gè)消息毅否。

四、四種引用

強(qiáng)引用(一般垃圾回收器不回收被強(qiáng)引用的對(duì)象)
在一般的Java程序中蝇刀,見(jiàn)到最多的就是強(qiáng)引用(strong reference)螟加。如Date date = new Date(),date就是一個(gè)對(duì)象的強(qiáng)引用吞琐。對(duì)象的強(qiáng)引用可以在程序中到處傳遞捆探。很多情況下,會(huì)同時(shí)有多個(gè)引用指向同一個(gè)對(duì)象站粟。強(qiáng)引用的存在限制了對(duì)象在內(nèi)存中的存活時(shí)間黍图。假如對(duì)象A中包含了一個(gè)對(duì)象B的強(qiáng)引用,那么一般情況下奴烙,對(duì)象B的存活時(shí)間就不會(huì)短于對(duì)象A助被。如果對(duì)象A沒(méi)有顯式的把對(duì)象B的引用設(shè)為null的話,就只有當(dāng)對(duì)象A被垃圾回收之后缸沃,對(duì)象B才不再有引用指向它恰起,才可能獲得被垃圾回收的機(jī)會(huì)。

軟引用 (內(nèi)存不足的時(shí)候趾牧,對(duì)象被回收)
軟引用(soft reference)在強(qiáng)度上弱于強(qiáng)引用检盼,通過(guò)類SoftReference來(lái)表示。它的作用是告訴垃圾回收器翘单,程序中的哪些對(duì)象是不那么重要吨枉,當(dāng)內(nèi)存不足的時(shí)候是可以被暫時(shí)回收的蹦渣。當(dāng)JVM中的內(nèi)存不足的時(shí)候,垃圾回收器會(huì)釋放那些只被軟引用所指向的對(duì)象貌亭。如果全部釋放完這些對(duì)象之后柬唯,內(nèi)存還不足,才會(huì)拋出OutOfMemory錯(cuò)誤圃庭。軟引用非常適合于創(chuàng)建緩存锄奢。當(dāng)系統(tǒng)內(nèi)存不足的時(shí)候,緩存中的內(nèi)容是可以被釋放的剧腻。

弱引用 (回收器只要發(fā)現(xiàn)一個(gè)對(duì)象的引用是全部是弱引用拘央,就會(huì)回收此對(duì)象、釋放內(nèi)存)
弱引用(weak reference)在強(qiáng)度上弱于軟引用书在,通過(guò)類WeakReference來(lái)表示灰伟。它的作用是引用一個(gè)對(duì)象,但是并不阻止該對(duì)象被回收儒旬。如果使用一個(gè)強(qiáng)引用的話栏账,只要該引用存在,那么被引用的對(duì)象是不能被回收的栈源。弱引用則沒(méi)有這個(gè)問(wèn)題挡爵。在垃圾回收器運(yùn)行的時(shí)候,如果一個(gè)對(duì)象的所有引用都是弱引用的話甚垦,該對(duì)象會(huì)被回收了讨。

Handler中使用弱引用來(lái)保存Activity對(duì)象,就是因?yàn)锳ctivity對(duì)象如果在Handler執(zhí)行過(guò)程中被銷(xiāo)毀回收制轰,那么如果不使用弱引用,這時(shí)Activity在Handler中就是屬于強(qiáng)引用胞谭,則不會(huì)被回收垃杖,這樣就會(huì)造成了內(nèi)存泄漏,而使用弱引用的話丈屹,就不會(huì)阻止Handler中的Activity對(duì)象被回收调俘。

五、Handler.postDelayed實(shí)現(xiàn)原理

這部分是對(duì)上面Handler原理的加以說(shuō)明

1.Handler.postDelayed方法其方法內(nèi)部旺垒,調(diào)用的是Handler的sendMessageDelayed方法:

public final boolean postDelayed(Runnable r, long delayMillis){
    return sendMessageDelayed(getPostMessage(r), delayMillis);
}

2.看下sendMessageDelayed源碼:

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

從這個(gè)方法中可以看出彩库,延遲時(shí)間其實(shí)是在SystemClock.uptimeMillis()這個(gè)時(shí)間的基礎(chǔ)上,加上延遲時(shí)間的先蒋,SystemClock.uptimeMillis()是從系統(tǒng)開(kāi)機(jī)啟動(dòng)到現(xiàn)在的時(shí)間骇钦,而且不包括休眠時(shí)間,因此這是一個(gè)相對(duì)時(shí)間竞漾。
用這樣的方式眯搭,而不是用當(dāng)前時(shí)間窥翩,主要也是因?yàn)镠andler會(huì)受到阻塞、掛起狀態(tài)鳞仙、睡眠等寇蚊,這些時(shí)候是不應(yīng)該執(zhí)行的。

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

這個(gè)方法做的工作棍好,就是將Message消息存放到MessageQueue中仗岸,但是并沒(méi)有做延遲存放的操作。存放的這個(gè)過(guò)程傳入uptimeMillis時(shí)間借笙,主要是為了對(duì)所有的message做排序扒怖,按需要執(zhí)行的順序?qū)essage排序放好,以便在next方法中順序取出提澎。
上面三個(gè)步驟是存放Message的姚垃,但是并沒(méi)有做任何延遲的處理,那么延遲的操作則不是在存的時(shí)候進(jìn)行的盼忌,那么只有可能是在取message的時(shí)候做了延遲處理

而上面關(guān)于Handler的消息處理分發(fā)部分的Looper.loop()的源碼解析可以看出积糯,loop方法內(nèi)部,并沒(méi)有等待或者阻塞等操作谦纱,而只有MessageQueue的next方法有一個(gè)注釋:可能會(huì)阻塞看成,那么看MessageQueue的next方法

4.MessageQueue的next()方法

在MessageQueue中,有一個(gè)是否阻塞的標(biāo)志位跨嘉,這個(gè)是用來(lái)判斷是否在pollOnce()的時(shí)候被阻塞等待了川慌。

    Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
// 是否退出的判斷
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        // 無(wú)限for循環(huán)
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                // 因?yàn)橄乱粭lMessage尚未到處理時(shí)間,則會(huì)將等待過(guò)程中需要處理的內(nèi)容交給CPU
                Binder.flushPendingCommands();
            }
            // 這里會(huì)有一個(gè)等待祠乃,在這個(gè)等待中設(shè)置了一個(gè)超時(shí)時(shí)間梦重,即postDelayed等方式發(fā)送的延遲處理的消息,其實(shí)是通過(guò)等待一定的時(shí)間再繼續(xù)執(zhí)行的方式來(lái)進(jìn)行
            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
// 如果當(dāng)前的msg不為空亮瓷,但是這個(gè)msg中的Handler為空琴拧,那么直接拿下一個(gè)消息,因?yàn)檫@個(gè)消息已經(jīng)沒(méi)有Handler來(lái)進(jìn)行處理
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    //判斷當(dāng)前時(shí)間是否小于下一條要處理的消息的時(shí)間
                    if (now < msg.when) {
                        // 下一條消息尚未就緒嘱支。 設(shè)置超時(shí)以在準(zhǔn)備就緒時(shí)喚醒蚓胸。
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        // 取出消息,如果前一個(gè)消息不為空除师,則將前一個(gè)消息的指向指到當(dāng)前消息的下一個(gè)
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            // 如果前一個(gè)消息為空沛膳,則說(shuō)明當(dāng)前消息是第一個(gè)
                            mMessages = msg.next;
                        }
                        // 將當(dāng)前消息的指向置為null
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

在這里重復(fù)一遍關(guān)于 MessageQueue.next()方法
當(dāng)nextPollTimeoutMillis是大于0的時(shí)候,那么下一次循環(huán)的時(shí)候會(huì)調(diào)用nativePollOnce方法汛聚,讓隊(duì)列阻塞锹安。但是如果當(dāng)前的隊(duì)列是阻塞的,這個(gè)時(shí)候加入了一個(gè)不是延遲發(fā)送的message的時(shí)候,就會(huì)將這個(gè)message加入隊(duì)首八毯,然后主動(dòng)喚醒隊(duì)列搓侄,處理這個(gè)消息

六、自定義手寫(xiě)Handler:

Handler實(shí)際上就是一個(gè)生產(chǎn)者與消費(fèi)者模式话速。

public class Handler {

    private MessageQueue mQueue;

    public Handler() {
        Looper mLooper = Looper.myLooper();
        mQueue = mLooper.mQueue;
    }

    /**
     * 發(fā)送消息讶踪,加入隊(duì)列
     * @param msg
     */
    public void sendMessage(Message msg){
        msg.target = this;
        // 傳入消息
        mQueue.enqueueMessage(msg);
    }

    /**
     * 處理消息
     * @param msg
     */
    public void handleMessage(Message msg){

    }

    /**
     * 分發(fā)消息
     * @param msg
     */
    public void dispatchMessage(Message msg){
        handleMessage(msg);
    }
}

Message類:

public class Message {
    // Message在使用Handler發(fā)送消息的時(shí)候,將Handler賦值給對(duì)應(yīng)的Message
    //用于在Looper.loop()獲取消息之后泊交,通過(guò)Handler實(shí)例分發(fā)消息
    Handler target;

    public Object obj;

    public int what;

    public Message() {
    }

    @Override
    public String toString() {
        return obj.toString();
    }
}

MessageQueue類:

public class MessageQueue {

    private Message[] items;

    // 入隊(duì)和出隊(duì)的索引位置
    private int putIndex;
    private int takeIndex;

    // 計(jì)數(shù)器
    private int count;

    private Lock lock;

    private Condition notEmpty;
    private Condition notFull;

    public MessageQueue() {
        items = new Message[50];

        // 可重入鎖
        lock = new ReentrantLock();

        notEmpty = lock.newCondition();
        notFull = lock.newCondition();
    }

    /**
     * 取出消息
     *
     * @return
     */
    public Message next() {
        Message msg = null;
        try {
            lock.lock();
            // 如果消息隊(duì)列為null乳讥,則等待新消息的入隊(duì)
            while (count == 0) {
                notEmpty.await();
            }
            msg = items[takeIndex];
            items[takeIndex] = null;
            takeIndex = (++takeIndex == items.length) ? 0 : takeIndex;
            count--;
            // 已經(jīng)消費(fèi)了一個(gè)消息,可以繼續(xù)入隊(duì)
            notFull.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return msg;
    }

    /**
     * 加入隊(duì)列
     *
     * @param msg
     */
    public void enqueueMessage(Message msg) {
        // 使用while循環(huán)廓俭,這樣的話云石,就可以避免不需要喚醒的子線程繼續(xù)等待。因?yàn)槭菃拘蚜巳垦衅梗锌赡軉拘蚜瞬恍枰粏拘训淖泳€程
        // 但是如果是使用if汹忠,則只會(huì)等待一次
        try {
            lock.lock();
            // 如果消息隊(duì)列已滿,則等待
            while (count == 50) {
                notFull.await();
            }
            items[putIndex] = msg;
            putIndex = (++putIndex == items.length) ? 0 : putIndex;
            count++;
            // 如果消息隊(duì)列不為null雹熬,則可以取出消息
            notEmpty.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
}

Looper類:

public class Looper {

    public MessageQueue mQueue;
    static ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();

    private Looper(){
        mQueue = new MessageQueue();
    }

    /**
     * 初始化Looper對(duì)象
     */
    public static void prepare(){
        if (sThreadLocal.get() != null){
            throw new RuntimeException("一個(gè)線程只能有一個(gè)looper");
        }
        sThreadLocal.set(new Looper());
    }

    /**
     * 獲取當(dāng)前線程的Looper對(duì)象
     * @return
     */
    public static Looper myLooper(){
        return sThreadLocal.get();
    }

    public static void loop(){
        Looper me = myLooper();

        if (me == null){
            throw new RuntimeException("當(dāng)前線程無(wú)Looper對(duì)象");
        }

        MessageQueue messageQueue = me.mQueue;
        for (;;){
            Message msg = messageQueue.next();
            if (msg != null){
                msg.target.dispatchMessage(msg);
            }
        }
    }
}

七宽菜、new Handler()兩種方式

    private Handler mHandler1 = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            return false;
        }
    });
    private Handler mHandler2 = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

一種是通過(guò)Handler的無(wú)參構(gòu)造器來(lái)創(chuàng)建,一種是通過(guò)有參構(gòu)造器來(lái)創(chuàng)建竿报。

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

在Handler中铅乡,是在dispatchMessage中來(lái)分發(fā)消息的,而這里的分發(fā)消息烈菌,是首先判斷mCallback是否為空來(lái)執(zhí)行的阵幸。

為什么使用Handler消息機(jī)制可以跨進(jìn)程?

因?yàn)樵谕粋€(gè)進(jìn)程里芽世,內(nèi)存是共享的挚赊,Looper對(duì)象創(chuàng)建在主線程,Handler對(duì)象創(chuàng)建在主線程济瓢,然后再子線程中使用這個(gè)Handler對(duì)象發(fā)送消息咬腕,因?yàn)镸essageQueue是在Looper對(duì)象中的,而Looper對(duì)象是在主線程中創(chuàng)建的葬荷,而且Handler對(duì)象是在主線程中創(chuàng)建的,所以Handler對(duì)象的handleMessage方法是在主線程中執(zhí)行的纽帖,又因?yàn)長(zhǎng)ooper.loop()是在主線程中執(zhí)行的宠漩,每次都是輪循MessageQueue獲取Message,然后通過(guò)主線程的Handler對(duì)象的dispatchMessage分發(fā)懊直,發(fā)送到handleMessage扒吁。

八、Handler內(nèi)存泄露的原因室囊?為什么其他的內(nèi)部類沒(méi)有說(shuō)過(guò)這個(gè)問(wèn)題雕崩?

(1)因?yàn)槎x的匿名內(nèi)部類魁索,會(huì)持有外部類的引用this,可以直接調(diào)用外部類的方法和屬性盼铁。
(2)生命周期的問(wèn)題粗蔚。因?yàn)镠andler.sendMessageAtTime會(huì)調(diào)用enqueueMessage,然后msg.target=this饶火,說(shuō)明Message會(huì)持有Handler鹏控,而Message在傳遞過(guò)程中,會(huì)有延時(shí)的情況肤寝,比如設(shè)置20s執(zhí)行当辐、20分鐘執(zhí)行,這樣就會(huì)出現(xiàn)Message持有了Handler鲤看,而Handler持有了Activity缘揪,但是當(dāng)Activity銷(xiāo)毀的時(shí)候,可能Message還沒(méi)處理义桂,還在延遲等待找筝,這樣就導(dǎo)致Activity根據(jù)JVM可達(dá)性分析算法得出Activity不能被GC回收。

http://www.reibang.com/p/e6877401a0e2

九澡刹、Handler#runWithScissors

在創(chuàng)建WMS對(duì)象的時(shí)候呻征,WMS的main方法中就通過(guò)調(diào)用DisplayThread.getHandler().runWithScissors()方法創(chuàng)建。
WMS的main方法是在SystemServer進(jìn)程的主線程調(diào)用的罢浇,然后在調(diào)用WMS的main方法的時(shí)候陆赋,通過(guò)DisplayThread這個(gè)HandlerThread,實(shí)現(xiàn)異步處理嚷闭,而這里的異步處理攒岛,其實(shí)是通過(guò)跨線程的一個(gè)同步,即通過(guò)DisplayThread中的Handler對(duì)象胞锰,調(diào)用runWithScissors方法灾锯,該方法其實(shí)是可以實(shí)現(xiàn)發(fā)送消息等待消息處理完成之后再繼續(xù)執(zhí)行runWithScissors方法調(diào)用位置之后的代碼,即等待消息處理完之后再進(jìn)行return WMS對(duì)象嗅榕。

public static WindowManagerService main(final Context context, final InputManagerService im,
        final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
        ActivityTaskManagerService atm) {
    return main(context, im, showBootMsgs, onlyCore, policy, atm,
            SurfaceControl.Transaction::new);
}
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
        final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
        ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
    // 這里其實(shí)就是在DisplayThread線程處理WMS的初始化
    DisplayThread.getHandler().runWithScissors(() ->
            sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
                    atm, transactionFactory), 0);
    return sInstance;
}

1.Handler#runWithScissors

根據(jù)上面的調(diào)用顺饮,上面的runWithScissors傳入的就是一個(gè)Runnable實(shí)例,只不過(guò)是采用了lambda表達(dá)式的做法凌那,所以Runnable的run()方法的方法體是就是:
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy, atm, transactionFactory), 0);

public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
    if (r == null) {
        throw new IllegalArgumentException("runnable must not be null");
    }
    if (timeout < 0) {
        throw new IllegalArgumentException("timeout must be non-negative");
    }
    // 如果調(diào)用runWithScissors方法的線程是與消息處理線程在同一個(gè)線程
    // 則直接執(zhí)行Runnable的run方法兼雄。
    if (Looper.myLooper() == mLooper) {
        r.run();
        return true;
    }
    // 如果調(diào)用runWithScissors方法的線程與消息處理線程不是同一個(gè),則創(chuàng)建一個(gè)BlockingRunnable
    BlockingRunnable br = new BlockingRunnable(r);
    // 并且調(diào)用BlockingRunnable.postAndWait方法
    // 這里的返回值會(huì)先等待帽蝶,等待DisplayThread線程中的Handler處理完
    // 消息之后赦肋,然后喚醒BlockingRunnable
    // 該Handler處理消息是在DisplayThread線程,而B(niǎo)lockingRunnable
    // 而B(niǎo)lockingRunnable調(diào)用wait并不會(huì)讓DisplayThread線程中的
    // Handler等待佃乘,Handler依然會(huì)處理消息囱井,處理消息其實(shí)就是調(diào)用了
    // BlockingRunnable.run()方法,當(dāng)BlockingRunnable.run()執(zhí)行完成
    // 就會(huì)調(diào)用notifyAll喚醒BlockingRunnable趣避,執(zhí)行postAndWait的return
    return br.postAndWait(this, timeout);
}

2.BlockingRunnable

private static final class BlockingRunnable implements Runnable {
    private final Runnable mTask;
    private boolean mDone;

    public BlockingRunnable(Runnable task) {
        mTask = task;
    }

    @Override
    public void run() {
        try {
            // 這個(gè)mTask其實(shí)就是runWithScissors中傳入的Runnable對(duì)象
            // BlockingRunnable的run方法的執(zhí)行庞呕,其實(shí)就是需要Handler遍歷到消息處理的時(shí)候
            // 然后處理這個(gè)BlockingRunnable消息,在處理BlockingRunnable消息
            // 的時(shí)候鹅巍,就會(huì)處理runWithScissors的參數(shù)中的Runnable這個(gè)mTask
            // 處理完成之后千扶,就會(huì)調(diào)用notifyAll喚醒等待線程,然后執(zhí)行postAndWait的return
            // 因?yàn)锽lockingRunnable的run方法是由Handler處理消息
            // 這個(gè)消息的處理與BlockingRunnable是在不同的線程
            // 所以BlockingRunnable等待的時(shí)候骆捧,其run方法是可以由handler消息處理
            mTask.run();
        } finally {
            synchronized (this) {
                mDone = true;
                notifyAll();
            }
        }
    }

    public boolean postAndWait(Handler handler, long timeout) {
        // 調(diào)用postAndWait的時(shí)候澎羞,先調(diào)用handler對(duì)象的post將消息發(fā)送出
        // 如果入隊(duì)成功,則為true敛苇,則開(kāi)始阻塞
        if (!handler.post(this)) {
            return false;
        }
        // 在上面的方法調(diào)用中妆绞,timeout=0,則阻塞枫攀。
        synchronized (this) {
            if (timeout > 0) {
                final long expirationTime = SystemClock.uptimeMillis() + timeout;
                // 如果mDone為false的時(shí)候括饶,則會(huì)等待,只有為true的時(shí)候来涨,會(huì)執(zhí)行
                while (!mDone) {
                    long delay = expirationTime - SystemClock.uptimeMillis();
                    if (delay <= 0) {
                        return false; // timeout
                    }
                    try {
                        wait(delay);
                    } catch (InterruptedException ex) {
                    }
                }
            } else {
                while (!mDone) {
                    try {
                        wait();
                    } catch (InterruptedException ex) {
                    }
                }
            }
        }
        return true;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末图焰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蹦掐,更是在濱河造成了極大的恐慌技羔,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卧抗,死亡現(xiàn)場(chǎng)離奇詭異藤滥,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)社裆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)拙绊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人泳秀,你說(shuō)我怎么就攤上這事标沪。” “怎么了嗜傅?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵谨娜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我磺陡,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任币他,我火速辦了婚禮坞靶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蝴悉。我一直安慰自己彰阴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布拍冠。 她就那樣靜靜地躺著尿这,像睡著了一般。 火紅的嫁衣襯著肌膚如雪庆杜。 梳的紋絲不亂的頭發(fā)上射众,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音晃财,去河邊找鬼叨橱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛断盛,可吹牛的內(nèi)容都是我干的罗洗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼钢猛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼伙菜!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起命迈,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贩绕,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后躺翻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體丧叽,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年公你,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了踊淳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡陕靠,死狀恐怖迂尝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情剪芥,我是刑警寧澤垄开,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站税肪,受9級(jí)特大地震影響溉躲,放射性物質(zhì)發(fā)生泄漏榜田。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一锻梳、第九天 我趴在偏房一處隱蔽的房頂上張望箭券。 院中可真熱鬧,春花似錦疑枯、人聲如沸辩块。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)废亭。三九已至,卻和暖如春具钥,著一層夾襖步出監(jiān)牢的瞬間豆村,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工氓拼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留你画,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓桃漾,卻偏偏與公主長(zhǎng)得像坏匪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子撬统,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355