深入了解Android消息機(jī)制和源碼分析(Java層和Native層)

本文章講解的內(nèi)容是深入了解Android消息機(jī)制和源碼分析(Java層和Native層),建議對著示例項(xiàng)目閱讀文章辟宗,示例項(xiàng)目鏈接如下:

HandlerDemo

本文章分析的相關(guān)的源碼基于Android SDK 29(Android 10.0爵赵,即Android Q)

概述

Android消息機(jī)制涉及到以下四個類

  • Message消息泊脐,它分為硬件產(chǎn)生的消息(例如:觸摸空幻、點(diǎn)擊)和軟件產(chǎn)生的消息。
  • MessageQueue消息隊(duì)列晨抡,它的作用是向消息池投遞消息和從消息池中取出消息氛悬。
  • Looper用于為線程運(yùn)行消息循環(huán)则剃,從MessageQueue(消息隊(duì)列)中取出消息耘柱,然后分發(fā)給Message(消息)對應(yīng)的宿主Handler。
  • Handler用于處理消息棍现,向消息池發(fā)送消息事件和處理消息事件调煎。

示例代碼

示例代碼如下所示:

package com.tanjiajun.handlerdemo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import java.lang.ref.WeakReference;

/**
 * Created by TanJiaJun on 2020/9/25.
 */
public class MainActivity extends AppCompatActivity {

    // 消息類別
    private static final int MESSAGE_CODE_MAIN = 0;

    // 繼承Handler,并且重寫它的handleMessage(Message msg)方法
    private static final class MainHandler extends Handler {

        // 聲明Activity的弱引用對象
        private final WeakReference<Activity> activityRef;

        MainHandler(Activity activity) {
            // 創(chuàng)建Activity的弱引用對象
            activityRef = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            // 得到MainActivity對象
            MainActivity activity = (MainActivity) activityRef.get();
            if (msg.what == MESSAGE_CODE_MAIN) {
                // 如果消息類別是MESSAGE_CODE_MAIN的值己肮,就執(zhí)行以下邏輯
                // 得到消息內(nèi)容
                String content = (String) msg.obj;
                // 設(shè)置TextView的文本為消息內(nèi)容
                activity.tvContent.setText(content);
            }
        }

    }

    private TextView tvContent;
    private MainHandler mainHandler;
    private Runnable runnable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvContent = findViewById(R.id.tv_content);
        // 創(chuàng)建MainHandler對象
        mainHandler = new MainHandler(this);
        // 創(chuàng)建Runnable對象
        runnable = new Runnable() {
            @Override
            public void run() {
                // 從消息池中取出消息
                Message message = mainHandler.obtainMessage();
                // 設(shè)置消息類別
                message.what = MESSAGE_CODE_MAIN;
                // 設(shè)置消息內(nèi)容
                message.obj = "譚嘉俊";
                // 將該消息添加到消息隊(duì)列的尾部
                mainHandler.sendMessage(message);
            }
        };
        // 創(chuàng)建線程士袄,并且啟動它
        new Thread(runnable).start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 刪除消息隊(duì)列中Runnable的普通消息
        mainHandler.removeCallbacks(runnable);
    }

}

使用靜態(tài)內(nèi)部類MainHandler的原因是靜態(tài)內(nèi)部類默認(rèn)不持有外部類的引用,同時使用弱引用持有Activity對象谎僻,當(dāng)Activity對象銷毀的時候娄柳,也就是沒有強(qiáng)引用持有Activity對象的時候,垃圾收集器就會回收它艘绍,防止出現(xiàn)內(nèi)存泄漏赤拒。

Message

Message(消息)分為硬件產(chǎn)生的消息(例如:觸摸、點(diǎn)擊)軟件產(chǎn)生的信息

Java層

成員變量

Message類的成員變量挎挖,源碼如下所示:

// Message.java
// 消息類別这敬,用戶定義的消息代碼,以便接受者能夠識別這個消息的內(nèi)容蕉朵,每個Handler都有自己的消息代碼名稱空間崔涂,因此不必?fù)?dān)心我們的Handler和其他的Handler會產(chǎn)生沖突
public int what;

// 參數(shù)1,如果我們只需要存儲int數(shù)據(jù)類型始衅,那么使用arg1和arg2是代替setData(Bundle data)方法最好的辦法
public int arg1;

// 參數(shù)2冷蚂,如果我們只需要存儲int數(shù)據(jù)類型,那么使用arg1和arg2是代替setData(Bundle data)方法最好的辦法
public int arg2;

// 消息內(nèi)容觅闽,要發(fā)送給接受者的任意對象帝雇,要注意的是,當(dāng)使用Messenger跨進(jìn)程發(fā)送消息時蛉拙,這個屬性無法傳輸自己實(shí)現(xiàn)Parcelable接口的類尸闸,只能傳輸Framework已有的實(shí)現(xiàn)Parcelable接口的類,但是我們可以使用setData(Bundle data)方法傳輸它
public Object obj;

// 可選的信使孕锄,具體語義由發(fā)送者和接受者決定
public Messenger replyTo;

// 未設(shè)置的uid吮廉,默認(rèn)值是-1
public static final int UID_NONE = -1;

// 發(fā)送消息的uid,它的值是UID_HOME畸肆,是可選字段宦芦,只對由Messenger發(fā)布的消息有效
public int sendingUid = UID_NONE;

// 消息進(jìn)入隊(duì)列的uid,它的值是UID_HOME轴脐,是可選字段调卑,要注意的是,它不支持外部應(yīng)用使用
public int workSourceUid = UID_NONE;

// 標(biāo)記消息正在使用狀態(tài)大咱,默認(rèn)值是1左移0位恬涧,也就是1
/*package*/ static final int FLAG_IN_USE = 1 << 0;

// 標(biāo)記消息是異步的,默認(rèn)值是1左移1位碴巾,也就是2
/*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;

// 要在copyFrom()方法中清除的標(biāo)記溯捆,默認(rèn)值是FLAG_IN_USE
/*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;

// 標(biāo)記
@UnsupportedAppUsage
/*package*/ int flags;

// 消息觸發(fā)時間
@UnsupportedAppUsage
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public long when;

// 設(shè)置一組任意數(shù)據(jù)值,通過setData(Bundle data)方法設(shè)值厦瓢,通過getData()或者peekData()取值
/*package*/ Bundle data;

// 消息接收者提揍,通過setTarget(Handler target)設(shè)值,通過getTarget()取值
@UnsupportedAppUsage
/*package*/ Handler target;

// 回調(diào)方法煮仇,只能通過getCallback()取值
@UnsupportedAppUsage
/*package*/ Runnable callback;

// 下一個存儲消息的結(jié)點(diǎn)劳跃,它不支持外部應(yīng)用使用
@UnsupportedAppUsage
/*package*/ Message next;


// 用于作為鎖對象
public static final Object sPoolSync = new Object();
// 存儲Message的頭結(jié)點(diǎn)
private static Message sPool;
// 消息池大小,默認(rèn)值是0
private static int sPoolSize = 0;

// 最大消息池大小浙垫,默認(rèn)值是50
private static final int MAX_POOL_SIZE = 50;

// 是否需要檢查回收
private static boolean gCheckRecycle = true;

我們看下與成員變量data相關(guān)的三個方法刨仑,分別是setData(Bundle data)方法强重、getData()方法和peekData()方法。

setData(Bundle data)方法可以設(shè)置一組任意數(shù)據(jù)值贸人,如果是int數(shù)據(jù)類型的值可以使用arg1arg2代替它间景,源碼如下所示:

// Message.java
public void setData(Bundle data) {
    this.data = data;
}

getData()方法可以惰性地獲取與這個事件關(guān)聯(lián)的一組數(shù)據(jù),可以通過setData(Bundle data)設(shè)置該值艺智,要注意的是倘要,當(dāng)使用Messenger跨進(jìn)程傳輸數(shù)據(jù)時,我們可以通過Bundle類的setClassLoader(ClassLoader loader)方法設(shè)置類加載器十拣,以便它可以在檢索對象實(shí)例化對象封拧,源碼如下所示:

// Message.java
public Bundle getData() {
    // 判斷data是否為空
    if (data == null) {
        // 如果是空的話,就創(chuàng)建一個新的Bundle對象
        data = new Bundle();
    }

    return data;
}

peekData()方法類似于getData()方法夭问,但是這個方法不會惰性創(chuàng)建泽西,如果Bundlenull,就返回null,源碼如下所示:

// Message.java
public Bundle peekData() {
    return data;
}

obtain()

obtain()方法可以從消息池中返回一個新的消息對象避免重新分配新的消息對象谷浅,建議使用這個方法得到Message對象而不是去new一個新的Message對象味抖,源碼如下所示:

// Message.java
public static Message obtain() {
    // 取Object對象作為鎖對象
    synchronized (sPoolSync) {
        if (sPool != null) {
            // 如果消息池不為空,就執(zhí)行以下邏輯
            // 獲得消息隊(duì)列的單向鏈表的頭結(jié)點(diǎn)
            Message m = sPool;
            // 把消息隊(duì)列的單向鏈表的下一個結(jié)點(diǎn)賦值給成員變量sPool
            sPool = m.next;
            // 將這個結(jié)點(diǎn)的下一個結(jié)點(diǎn)賦值為空灰粮,相當(dāng)于將這個結(jié)點(diǎn)從消息隊(duì)列的單向鏈表中刪除
            m.next = null;
            // 將這個消息標(biāo)記為不再使用仔涩,正在使用狀態(tài)是FLAG_IN_USE,它的值是1左移0位粘舟,
            m.flags = 0;
            // 自減消息池的數(shù)量
            sPoolSize--;
            // 返回消息
            return m;
        }
    }
    // 如果消息池為空熔脂,就創(chuàng)建新的Message對象,并且返回它
    return new Message();
}

recycle()

recycle()方法可以把不再使用的消息對象添加到消息池柑肴,調(diào)用這個方法后霞揉,這個消息對象就不能使用,因?yàn)樗呀?jīng)被有效地釋放嘉抒,回收正在排隊(duì)的消息回收正在傳遞給Handler的消息都是錯誤的零聚,源碼如下所示:

// Message.java
public void recycle() {
    if (isInUse()) {
        if (gCheckRecycle) {
            // 如果這個消息是正在使用狀態(tài)袍暴,就拋出IllegalStateException異常
            throw new IllegalStateException("This message cannot be recycled because it "
                    + "is still in use.");
        }
        return;
    }
    // 調(diào)用recycleUnchecked()方法
    recycleUnchecked();
}

// 回收不再使用的消息些侍,添加到消息池
@UnsupportedAppUsage
void recycleUnchecked() {
    // 將消息標(biāo)記為FLAG_IN_USE狀態(tài),所有參數(shù)設(shè)置為初始化狀態(tài)
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = UID_NONE;
    workSourceId = UID_NONE;
    when = 0;
    target = null;
    callback = null;
    data = null;

    // 取Object對象作為鎖對象
    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            // 如果消息池的數(shù)量小于MAX_POOL_SIZE的值(50)政模,就將當(dāng)前消息添加到消息隊(duì)列的單向鏈表的頭部
            // 將原來的頭結(jié)點(diǎn)賦值給下一個結(jié)點(diǎn)
            next = sPool;
            // 將這個消息設(shè)為頭結(jié)點(diǎn)
            sPool = this;
            // 自增消息池數(shù)量
            sPoolSize++;
        }
    }
}

native層

Message結(jié)構(gòu)體在Looper.h文件中岗宣,源碼如下所示:

// system/core/libutils/include/utils/Looper.h
struct Message {
    Message() : what(0) { }
    Message(int w) : what(w) { }

    // 消息類別
    int what;
};

MessageQueue

MessageQueue(消息隊(duì)列)存放消息的隊(duì)列,它的數(shù)據(jù)結(jié)構(gòu)單向鏈表淋样,每個線程內(nèi)部都維護(hù)著一個消息隊(duì)列耗式,它的作用是向消息池中投遞消息從消息池中取出消息,它是消息機(jī)制Java層C++層連接紐帶

Java層

native方法

MessageQueue的源碼中刊咳,調(diào)用了多個C++方法彪见,有如下native方法,源碼如下所示:

// MessageQueue.java
// 初始化
private native static long nativeInit();
// 銷毀
private native static void nativeDestroy(long ptr);
// 取出消息隊(duì)列中的消息娱挨,形式參數(shù)timeoutMillis是超時時間
private native void nativePollOnce(long ptr, int timeoutMillis);
// 喚醒線程
private native static void nativeWake(long ptr);
// 線程是否處于阻塞狀態(tài)
private native static boolean nativeIsPolling(long ptr);
// 設(shè)置文件描述符
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);

enqueueMessage(Message msg, long when)

enqueueMessage(Message msg, long when)方法的作用是添加一條普通消息到消息隊(duì)列中余指,源碼如下所示:

// MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        // 如果消息沒有接收者,就拋出IllegalArgumentException異常
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        // 如果消息正在使用跷坝,就拋出IllegalStateException異常
        throw new IllegalStateException(msg + " This message is already in use.");
    }

    // 取NessageQueue對象作為鎖對象
    synchronized (this) {
        if (mQuitting) {
            // 如果正在退出酵镜,就執(zhí)行以下邏輯
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            // 打印消息的接收者
            Log.w(TAG, e.getMessage(), e);
            // 調(diào)用recycle()方法,回收消息
            msg.recycle();
            return false;
        }

        // 將消息標(biāo)記為正在使用狀態(tài)
        msg.markInUse();
        // 設(shè)置消息的觸發(fā)時間
        msg.when = when;
        // 取消息隊(duì)列的單向鏈表的頭結(jié)點(diǎn)存儲的消息
        Message p = mMessages;
        // 這個變量用來判斷是否需要喚醒線程
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            // 如果是消息隊(duì)列為空柴钻,或者沒有設(shè)置觸發(fā)時間淮韭,或者觸發(fā)時間比頭結(jié)點(diǎn)的消息要早,就插入消息隊(duì)列的單向鏈表的頭部
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // 將消息按著時間順序插入到消息隊(duì)列的單向鏈表中贴届,通常不需要喚醒事件隊(duì)列靠粪,除非隊(duì)列的頭部有一個屏障,并且消息是隊(duì)列中最早的異步消息
            // needWake的值是由線程是否被阻塞毫蚓,并且消息存在宿主Handler庇配,并且消息是異步的決定
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            // 循環(huán)執(zhí)行
            for (;;) {
                // 采用快慢指針,prev是慢指針绍些,p是快指針
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    // 如果已經(jīng)到了消息隊(duì)列的單向鏈表的尾部捞慌,或者有觸發(fā)時間早于該消息的消息,就結(jié)束循環(huán)
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    // 如果消息是是異步柬批,在它前面的消息也是異步的啸澡,就不用去喚醒線程
                    needWake = false;
                }
            }
            // 將消息插入到消息隊(duì)列的單向鏈表中
            // 和p == prev.next同義
            msg.next = p;
            prev.next = msg;
        }

        // 消息沒有退出,可以認(rèn)為這個時候mPtr != 0
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

上面也提到了氮帐,MessageQueue數(shù)據(jù)結(jié)構(gòu)單向鏈表嗅虏,從上面的源碼可得知,它是按著時間順序進(jìn)行排列的上沐,頭結(jié)點(diǎn)存儲的是最先分發(fā)的消息皮服,當(dāng)要添加一條消息到消息隊(duì)列時,如果消息隊(duì)列為空参咙,或者消息沒有設(shè)置觸發(fā)時間龄广,或者消息觸發(fā)時間比頭結(jié)點(diǎn)的消息要早,就插入到單向鏈表的頭部蕴侧,否則择同,就按著時間順序插入到單向鏈表中。

next()

next()方法的作用是從消息池中取出消息净宵,它會被下面講解到Looper.loop()方法調(diào)用敲才,源碼如下所示:

// MessageQueue.java
@UnsupportedAppUsage
Message next() {
    // mPtr是從native方法中的到的NativeMessageQueue地址
    final long ptr = mPtr;
    if (ptr == 0) {
        // 如果mPtr是0裹纳,說明消息隊(duì)列不存在或者被清理掉了
        return null;
    }

    // 待處理的IdleHandler數(shù)量,默認(rèn)值是-1
    int pendingIdleHandlerCount = -1;
    // 線程被阻塞的時間紧武,-1是一直阻塞剃氧,大于等于0是不阻塞
    int nextPollTimeoutMillis = 0;
    // 循環(huán)執(zhí)行
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            // 如果nextPollTimeoutMillis不等于0,就調(diào)用Binder.flushPendingCommands()方法阻星,把要釋放的對象釋放
            Binder.flushPendingCommands();
        }

        // 阻塞線程
        nativePollOnce(ptr, nextPollTimeoutMillis);

        // 取MessageQueue對象作為鎖對象
        synchronized (this) {
            // 得到當(dāng)前時間
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // 如果是同步屏障消息她我,就循環(huán)執(zhí)行,找到第一條異步的消息
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                // 如果消息隊(duì)列中有可取出的消息迫横,就執(zhí)行以下邏輯
                if (now < msg.when) {
                    // 如果待取出的消息還沒到應(yīng)該要處理的時間番舆,就讓線程阻塞到應(yīng)該要處理的時間
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 如果待取出的消息到達(dá)應(yīng)該處理的時間,就直接取出消息
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    // 從消息隊(duì)列中的單向鏈表中刪除該消息的結(jié)點(diǎn)
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    // 設(shè)置消息的狀態(tài)為正在使用狀態(tài)
                    msg.markInUse();
                    // 返回消息矾踱,結(jié)束循環(huán)恨狈,結(jié)束next()方法
                    return msg;
                }
            } else {
                // 如果消息隊(duì)列沒有可取出消息,就一直讓線程阻塞
                nextPollTimeoutMillis = -1;
            }

            if (mQuitting) {
                // 如果消息隊(duì)列已經(jīng)退出呛讲,就處理退出消息
                dispose();
                return null;
            }

            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                // 如果第一次空閑禾怠,就會得到IdleHandler數(shù)組的大小,要注意的是贝搁,IdleHandler僅在消息隊(duì)列為空或者只有一個將要在將來執(zhí)行的消息(可能是個同步屏障)
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // 如果沒有要運(yùn)行的IdleHandler吗氏,就進(jìn)入下此循環(huán),并且阻塞線程
                mBlocked = true;
                continue;
            }

            // 執(zhí)行到這里雷逆,證明線程中有待處理的IdleHandler
            if (mPendingIdleHandlers == null) {
                // 如果mPendingIdleHandlers為空弦讽,就初始化IdleHandler數(shù)組,最小長度是4
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            // 從IdleHandler數(shù)組中取出待處理的IdleHandler
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // 運(yùn)行IdleHandler膀哲,只能在第一次迭代中執(zhí)行以下邏輯
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            // 從mPendingIdleHandlers數(shù)組中取出idleHandler
            final IdleHandler idler = mPendingIdleHandlers[i];
            // 釋放引用
            mPendingIdleHandlers[i] = null;

            // IdleHandler的執(zhí)行模式往产,true是執(zhí)行一次,false是總是執(zhí)行
            boolean keep = false;
            try {
                // 得到IdleHandler的執(zhí)行模式
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            // 通過IdleHandler的執(zhí)行模式來判斷是否需要從mIdleHandlers數(shù)組中刪除對應(yīng)的IdleHandler
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // 將IdleHandler的計數(shù)數(shù)量重置為0某宪,這樣就不會再運(yùn)行它們了
        pendingIdleHandlerCount = 0;

        // 在調(diào)用執(zhí)行IdleHandler的邏輯的時候仿村,可能已經(jīng)有新的消息添加到消息隊(duì)列,所以在這里就不用去阻塞線程兴喂,直接去查看還有沒有新的消息
        nextPollTimeoutMillis = 0;
    }
}

要注意的是蔼囊,nativePollOnce(long ptr, int timeoutMillis)方法的作用是阻塞線程nextPollTimeoutMillis在下一個消息到來之前衣迷,還需要等待的時長畏鼓,-1表示消息隊(duì)列中沒有消息線程被阻塞蘑险,大于等于0表示線程不阻塞滴肿;當(dāng)有待處理的消息時岳悟,就會在nativePollOnce(long ptr, int timeoutMillis)方法返回后佃迄,從消息池(mMessages)中取出消息(Message)泼差;當(dāng)處于線程空閑狀態(tài)時,就會執(zhí)行IdleHandler的方法呵俏。

quit(boolean safe)

quit(boolean safe)方法的作用是退出當(dāng)前消息隊(duì)列堆缘,清空消息隊(duì)列中的所有消息,源碼如下所示:

// MessageQueue.java
void quit(boolean safe) {
    if (!mQuitAllowed) {
        // 如果是不允許退出消息隊(duì)列的狀態(tài)普碎,就拋出IllegalStateException異常
        throw new IllegalStateException("Main thread not allowed to quit.");
    }

    synchronized (this) {
        if (mQuitting) {
            // 如果已經(jīng)退出消息隊(duì)列吼肥,就結(jié)束該方法
            return;
        }
        // 標(biāo)記為已退出消息隊(duì)列
        mQuitting = true;

        if (safe) {
            // 如果是安全退出消息隊(duì)列,就調(diào)用removeAllFutureMessageLocked()方法麻车,刪除消息隊(duì)列中沒有被處理的消息
            removeAllFutureMessagesLocked();
        } else {
            // 如果不是安全退出消息隊(duì)列缀皱,就調(diào)用removeAllMessagesLocked()方法,刪除消息隊(duì)列中所有的消息
            removeAllMessagesLocked();
        }

        // 喚醒線程
        nativeWake(mPtr);
    }
}

removeAllFutureMessagesLocked()

removeAllFutureMessagesLocked()方法的作用是刪除消息隊(duì)列中沒有被處理的消息动猬,源碼如下所示:

// MessageQueue.java
private void removeAllFutureMessagesLocked() {
    // 獲取當(dāng)前系統(tǒng)時間
    final long now = SystemClock.uptimeMillis();
    Message p = mMessages;
    if (p != null) {
        if (p.when > now) {
            // 如果消息的觸發(fā)時間晚于當(dāng)前時間啤斗,就調(diào)用removeAllMessagesLocked()方法,刪除消息隊(duì)列中的所有的消息
            removeAllMessagesLocked();
        } else {
            // 如果消息的觸發(fā)時間早于當(dāng)前時間赁咙,就執(zhí)行以下邏輯
            Message n;
            // 循環(huán)執(zhí)行
            for (;;) {
                n = p.next;
                if (n == null) {
                    // 如果消息為空钮莲,就結(jié)束該方法
                    return;
                }
                if (n.when > now) {
                    // 如果消息的觸發(fā)時間早于當(dāng)前時間,就結(jié)束該循環(huán)
                    break;
                }
                p = n;
            }
            p.next = null;
            do {
                // n是晚于當(dāng)前時間的消息
                p = n;
                n = p.next;
                // 調(diào)用recycleUnchecked()方法彼水,回收從n之后的消息到消息池中崔拥,也就是回收所有晚于當(dāng)前時間的消息到消息池中
                p.recycleUnchecked();
            } while (n != null);
        }
    }
}

removeAllMessagesLocked()

removeAllMessagesLocked()方法的作用是刪除消息隊(duì)列中的所有的消息,源碼如下所示:

// MessageQueue.java
private void removeAllMessagesLocked() {
    Message p = mMessages;
    while (p != null) {
        Message n = p.next;
        // 調(diào)用recycleUnchecked()方法凤覆,將消息回收到消息池中
        p.recycleUnchecked();
        p = n;
    }
    mMessages = null;
}

removeMessages(Handler h, Runnable r, Object object)

removeMessages(Handler h, Runnable r, Object object)方法的作用是刪除消息隊(duì)列中符合條件的普通消息链瓦,源碼如下所示:

// MessageQueue.java
void removeMessages(Handler h, int what, Object object) {
    if (h == null) {
        // 如果Handler為空,就返回
        return;
    }

    // 取MessageQueue對象作為鎖對象
    synchronized (this) {
        Message p = mMessages;

        // 從消息隊(duì)列的單向鏈表的頭結(jié)點(diǎn)開始盯桦,刪除所有符合條件的消息
        while (p != null && p.target == h && p.what == what
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            // 調(diào)用recycleUnchecked()方法澡绩,將消息回收到消息池中
            p.recycleUnchecked();
            p = n;
        }

        // 刪除剩余符合條件的消息
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && n.what == what
                    && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    // 調(diào)用recycleUnchecked()方法,將消息回收到消息池中
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}

removeMessages(Handler h, Runnable r, Object object)方法邏輯中有兩個while循環(huán)俺附,第一個循環(huán)的作用是從消息隊(duì)列的單向鏈表的頭結(jié)點(diǎn)開始肥卡,刪除符合條件的消息第二個循環(huán)的作用是刪除剩余符合條件的消息事镣。

postSyncBarrier(long when)

postSyncBarrier(long when)方法的作用是添加一條同步屏障消息到消息隊(duì)列中步鉴。

普通消息同步屏障消息的區(qū)別是:普通消息的target變量不為空同步屏障消息的變量target為空璃哟,同步屏障的作用是在處理消息時氛琢,優(yōu)先處理異步的消息起到過濾的作用随闪。

源碼如下所示:

// MessageQueue.java
@TestApi
public int postSyncBarrier() {
    // 調(diào)用postSyncBarrier(long when)阳似,形式參數(shù)when是當(dāng)前時間
    return postSyncBarrier(SystemClock.uptimeMillis());
}

private int postSyncBarrier(long when) {
    // 去MessageQueue對象作為鎖對象
    synchronized (this) {
        // 得到同步屏障token
        final int token = mNextBarrierToken++;
        // 從消息池中取出消息,并沒有對變量target賦值铐伴,所以為空
        final Message msg = Message.obtain();
        // 標(biāo)記消息為正在使用狀態(tài)
        msg.markInUse();
        // 設(shè)置觸發(fā)時間
        msg.when = when;
        // 將token賦值給變量arg1
        msg.arg1 = token;

        Message prev = null;
        Message p = mMessages;
        if (when != 0) {
            while (p != null && p.when <= when) {
                // 如果觸發(fā)時間不為空撮奏,就在消息隊(duì)列中按照時間順序找到它的位置
                prev = p;
                p = p.next;
            }
        }
        if (prev != null) {
            // 如果不是消息隊(duì)列的單向鏈表的頭結(jié)點(diǎn)俏讹,就把同步屏障消息添加到消息隊(duì)列中
            msg.next = p;
            prev.next = msg;
        } else {
            // 如果是消息隊(duì)列的單向鏈表的頭結(jié)點(diǎn),就把同步屏障消息添加到頭部
            msg.next = p;
            mMessages = msg;
        }
        // 同步屏障消息添加成功畜吊,就返回對應(yīng)的token
        return token;
    }
}

token是的作用是在刪除同步屏障消息時泽疆,可以找到對應(yīng)的消息,下面會講解玲献。

removeSyncBarrier(int token)

removeSyncBarrier(int token)方法的作用是刪除消息隊(duì)列中符合條件的同步屏障消息殉疼,源碼如下所示:

// MessageQueue.java
@TestApi
public void removeSyncBarrier(int token) {
    // 取MessageQueue對象作為鎖對象
    synchronized (this) {
        Message prev = null;
        Message p = mMessages;
        // 循環(huán)遍歷消息隊(duì)列的單向鏈表,找出target為空捌年,并且變量args是對應(yīng)token的消息
        while (p != null && (p.target != null || p.arg1 != token)) {
            prev = p;
            p = p.next;
        }
        if (p == null) {
            // 如果p為空瓢娜,證明沒找到對應(yīng)token的同步屏障消息,拋出IllegalStateException異常
            throw new IllegalStateException("The specified message queue synchronization "
                    + " barrier token has not been posted or has already been removed.");
        }
        // 該變量用于判斷是否需要喚醒線程
        final boolean needWake;
        if (prev != null) {
            // 如果不是消息隊(duì)列的單向鏈表的頭結(jié)點(diǎn)礼预,就不需要喚醒線程恋腕,證明在它前面還有其他消息
            prev.next = p.next;
            needWake = false;
        } else {
            // 如果是消息隊(duì)列中的單向鏈表的頭結(jié)點(diǎn),就執(zhí)行以下邏輯
            mMessages = p.next;
            // 如果消息隊(duì)列為空或者下一條消息是普通消息逆瑞,就需要喚醒線程荠藤,否則,就不需要喚醒線程
            needWake = mMessages == null || mMessages.target != null;
        }
        // 將消息回收到消息池中
        p.recycleUnchecked();

        if (needWake && !mQuitting) {
            // 如果需要喚醒線程获高,并且循環(huán)還沒退出哈肖,就調(diào)用nativeWake(long ptr)方法,喚醒線程
            nativeWake(mPtr);
        }
    }
}

同步屏障使用場景

在類ViewRootImplscheduleTraversals()方法和unscheduleTraversals()方法中使用到了同步屏障念秧。

scheduleTraversals()方法的作用是執(zhí)行添加同步屏障消息淤井,View更新相關(guān)的方法都有調(diào)用scheduleTraversals()方法,目的是讓Android系統(tǒng)優(yōu)先執(zhí)行跟View更新相關(guān)的異步消息摊趾,優(yōu)先處理跟View更新相關(guān)的邏輯币狠,源碼如下所示:

// ViewRootImpl.java
@UnsupportedAppUsage
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        // 添加同步屏障消息
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        // 執(zhí)行添加同步屏障消息
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        if (!mUnbufferedInputDispatch) {
            scheduleConsumeBatchedInput();
        }
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

unscheduleTraversals()方法的作用是執(zhí)行刪除同步屏障消息任務(wù),源碼如下所示:

// ViewRootImpl.java
void unscheduleTraversals() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        // 刪除同步屏障消息
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        // 執(zhí)行刪除同步屏障消息
        mChoreographer.removeCallbacks(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    }
}

IdleHandler

IdleHandler是一個回調(diào)接口砾层,用于發(fā)現(xiàn)線程什么時候需要阻塞更多消息漩绵。

如果消息隊(duì)列為空,它就會阻塞線程等待消息到來肛炮,這種狀態(tài)稱之為空閑狀態(tài)止吐。

源碼如下所示:

// MessageQueue.java
public static interface IdleHandler {
    boolean queueIdle();
}

queueIdle()方法會在當(dāng)消息隊(duì)列處理完所有消息并且等待更多消息的時候調(diào)用侨糟,也就是處于空閑狀態(tài)碍扔,返回true代表只執(zhí)行一次返回false代表會一直執(zhí)行這個方法秕重。

IdleHandler有如下使用場景:

  • 提供一個Activity繪制完成的回調(diào)不同。
  • 結(jié)合HandlerThread,提供一個單線程消息通知器。

Native層

MessageQueue是連接Java層Native層的紐帶二拐,Java層MessageQueueNative層MessageQueue是通過JNI(Java Native Interface)建立關(guān)聯(lián)服鹅,Java層可以向MessageQueue添加MessageNative層也可以向MessageQueue添加Message卓鹿。

nativeInit()

nativeInit()方法在MessageQueue類的構(gòu)造方法中調(diào)用菱魔,源碼如下所示:

// MessageQueue.java
@UnsupportedAppUsage
@SuppressWarnings("unused")
private long mPtr;

MessageQueue(boolean quitAllowed) {
    mQuitAllowed = quitAllowed;
    // 調(diào)用nativeInit()函數(shù)
    mPtr = nativeInit();
}

nativeInit()方法通過JNI調(diào)用android_os_MessageQueue_nativeInit(JNIEnv env, jclass clazz)*函數(shù)留荔,該函數(shù)的源碼如下所示:

// frameworks/base/core/jni/android_os_MessageQueue.cpp
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
    // 初始化Native層的MessageQueue
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
    if (!nativeMessageQueue) {
        // 在JNI中拋出RuntimeException異常
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return 0;
    }

    // 增加引用計數(shù)
    nativeMessageQueue->incStrong(env);
    // 將nativeMessageQueue的指針強(qiáng)轉(zhuǎn)成JNI的jlong類型
    return reinterpret_cast<jlong>(nativeMessageQueue);
}

成員變量mPtrnativeInit()函數(shù)的返回值吟孙,它是Native層NativeMessage指針盲赊。

看下NativeMessage構(gòu)造函數(shù)帚称,源碼如下所示:

// frameworks/base/core/jni/android_os_MessageQueue.cpp
NativeMessageQueue::NativeMessageQueue() :
        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
    // 從ThreadLocal中取出Looper實(shí)例,相當(dāng)于Java層的Looper.myLooper()方法
    mLooper = Looper::getForThread();
    if (mLooper == NULL) {
        // 如果ThreadLocal中沒有Looper實(shí)例埋涧,就執(zhí)行以下邏輯
        // 創(chuàng)建Native層的Looper實(shí)例
        mLooper = new Looper(false);
        // 將Looper對象存儲到ThreadLocal碘勉,相當(dāng)于Java層的ThreadLocal的set(T value)方法
        Looper::setForThread(mLooper);
    }
}

看下Looper構(gòu)造函數(shù)巷挥,源碼如下所示:

// system/core/libutils/Looper.cpp
Looper::Looper(bool allowNonCallbacks)
    : mAllowNonCallbacks(allowNonCallbacks),
      mSendingMessage(false),
      mPolling(false),
      mEpollRebuildRequired(false),
      mNextRequestSeq(0),
      mResponseIndex(0),
      mNextMessageUptime(LLONG_MAX) {
    // eventfd(unsigned int __initial_value, int __flags)函數(shù)用來創(chuàng)建一個事件對象,它返回一個文件描述符來代表這個事件對象验靡,我們可以使用它來調(diào)用對象倍宾,這里是創(chuàng)建一個喚醒事件的文件描述符
    mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
    LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));

    // AutoMutex _l函數(shù)的作用是對mLock加鎖,執(zhí)行完成后自動釋放鎖胜嗓,它利用了C++的構(gòu)造函數(shù)和析構(gòu)函數(shù)的自動加鎖和自動釋放鎖
    AutoMutex _l(mLock);
    // 重建mPoll事件
    rebuildEpollLocked();
}

看下rebuildEpollLocked()函數(shù)高职,源碼如下所示:

// system/core/libutils/Looper.cpp
void Looper::rebuildEpollLocked() {
    if (mEpollFd >= 0) {
#if DEBUG_CALLBACKS
        ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
#endif
        // 如果epoll文件描述符大于等于0,也就是已經(jīng)有一個辞州,就關(guān)閉舊的epoll實(shí)例
        mEpollFd.reset();
    }

    // 創(chuàng)建新的epoll實(shí)例怔锌,并且注冊wake管道,參數(shù)是表示監(jiān)聽的文件描述符數(shù)目变过,它向內(nèi)核申請一段內(nèi)存空間
    mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));

    struct epoll_event eventItem;
    // 將未使用數(shù)據(jù)區(qū)域歸零
    memset(& eventItem, 0, sizeof(epoll_event));
    // 設(shè)置eventItem為可讀事件
    eventItem.events = EPOLLIN;
    // 把mWakeEventFd賦值給eventItem
    eventItem.data.fd = mWakeEventFd.get();
    // 將mWakeEventFd(喚醒事件)添加到mEpollFd(epoll實(shí)例)
    int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
                        strerror(errno));

    for (size_t i = 0; i < mRequests.size(); i++) {
        const Request& request = mRequests.valueAt(i);
        struct epoll_event eventItem;
        request.initEventItem(&eventItem);

        // 將request隊(duì)列的事件分別添加到epoll實(shí)例
        int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, request.fd, &eventItem);
        if (epollResult < 0) {
            ALOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",
                  request.fd, strerror(errno));
        }
    }
}

文件描述符

Linux內(nèi)核(kernel)使用文件描述符(File Descriptor)來訪問文件埃元,它是一個非負(fù)整數(shù),它是一個文件索引媚狰。新建文件或者打開已經(jīng)存在的文件的時候岛杀,Linux內(nèi)核會返回一個文件描述符

epoll

epoll是一種當(dāng)文件描述符內(nèi)核緩沖區(qū)不是空的時候崭孤,發(fā)出可讀信號進(jìn)行通知楞件;當(dāng)寫緩沖區(qū)還沒滿的時候,發(fā)出可寫信號的進(jìn)行通知的機(jī)制裳瘪,它是一種I/O多路復(fù)用機(jī)制土浸,可以同時監(jiān)控多個文件描述符

epollLinux內(nèi)核2.6中提出的彭羹,它比selectpoll強(qiáng)大黄伊;epoll沒有描述符數(shù)量限制,更加靈活派殷,它使用一個文件描述符(File Descriptor还最,簡稱:fd)管理多個描述符墓阀;epoll是Linux最高效的I/O復(fù)用機(jī)制,它將用戶空間的文件描述符的事件存儲到Linux內(nèi)核的一個事件表中拓轻,從而使用戶空間和內(nèi)核空間的復(fù)制只需要一次斯撮,而且它可以在一個地方等待多個文件句柄的I/O事件

epoll的操作可以分為三個函數(shù)

int epoll_create(int size)

int epoll_create(int size)函數(shù)的作用是創(chuàng)建一個epoll的句柄扶叉。

參數(shù)size初次分配的需要監(jiān)聽的描述符數(shù)量勿锅,如果后面空間不足的時候,就會進(jìn)行動態(tài)擴(kuò)容枣氧。

創(chuàng)建完epoll句柄后溢十,就會占用一個文件描述符的值,并且返回這個值达吞。

要注意的是张弛,使用完epoll后,需要調(diào)用close()函數(shù)關(guān)閉酪劫,否則吞鸭,會耗盡文件描述符

int epoll_ctl(int __epoll_fd, int __op, int __fd, struct epoll_event* __event)

int epoll_ctl(int __epoll_fd, int __op, int __fd, struct epoll_event __event)函數(shù)的作用是對需要監(jiān)聽的文件描述符執(zhí)行op操作覆糟,例如:將文件描述符加入到epoll句柄*刻剥。

參數(shù)如下所示:

epoll_fd

epoll_fdepoll_create(int size)返回值,它生成epoll專用的文件描述符搪桂。

op

opop操作透敌,它用三個宏表示,如下所示:

  • EPOLL_CTL_ADD注冊新的文件描述符到epoll文件描述符中踢械。
  • EPOLL_CTL_MOD修改已經(jīng)注冊的文件描述符的監(jiān)聽事件酗电。
  • EPOLL_CTL_DEL從epoll文件描述符中刪除一個文件描述符。
fd

fd需要監(jiān)聽的文件描述符内列。

event

event需要監(jiān)聽的事件撵术,它的類型是epoll_eventepoll_event的源碼如下所示:

// bionic/libc/include/bits/epoll_event.h
struct epoll_event {
  // epoll事件
  uint32_t events;
  // 數(shù)據(jù)
  epoll_data_t data;
}

events的值有如下:

  • EPOLLIN表示epoll的文件描述符有可讀數(shù)據(jù)话瞧。
  • EPOLLOUT表示epoll的文件描述符有可寫數(shù)據(jù)嫩与。
  • EPOLLPRI表示epoll的文件描述符有緊急的可讀數(shù)據(jù)。
  • EPOLLERR表示epoll的文件描述符發(fā)生錯誤交排。
  • EPOLLHUP表示epoll的文件描述符被掛斷划滋。
  • EPOLLET表示將epoll設(shè)置為邊緣觸發(fā)(Edge Triggered)模式,這是相對于水平觸發(fā)(Level Triggered)埃篓。
  • EPOLLONESHOT表示只監(jiān)聽一次事件处坪,當(dāng)監(jiān)聽完這次事件后,如果需要繼續(xù)監(jiān)聽,就需要再次把對應(yīng)的事件加入到epoll隊(duì)列中同窘。

epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)

epoll_wait(int epfd, struct epoll_event events, int maxevents, int timeout)函數(shù)的作用是等待事件上報*玄帕。

參數(shù)如下所示:

  • epfdepoll_create(int size)返回值,它生成epoll專用的文件描述符想邦。
  • events需要監(jiān)聽的事件裤纹,前面講解過,這里就不再贅述丧没。
  • maxevents:每次能處理的最大事件數(shù)量鹰椒。
  • timeout:等待I/O事件發(fā)生的超時值-1阻塞骂铁,0非阻塞吹零。

小結(jié)

nativeInit()方法執(zhí)行如下邏輯:

  • 創(chuàng)建NativeMessageQueue對象罩抗,增加其引用計數(shù)拉庵,并且將Native層NativeMessageQueue指針mPtr保存到Java層MessageQueue
  • 創(chuàng)建Native層Looper對象套蒂。
  • 調(diào)用epollepoll_create(int size)函數(shù)和epoll_ctl(int __epoll_fd, int __op, int __fd, struct epoll_event __event)函數(shù)來完成對喚醒事件(mWakeEventFd)Request隊(duì)列事件(mRequests)的監(jiān)聽钞支,它們都是可讀事件*。

nativeDestroy(long ptr)

nativeDestroy(long ptr)方法的作用是回收操刀。

nativeDestroy(long ptr)方法在MessageQueue類的dispose()方法調(diào)用烁挟,當(dāng)需要退出消息隊(duì)列的時候就會調(diào)用,源碼如下所示:

// MessageQueue.java
private void dispose() {
    if (mPtr != 0) {
        // 調(diào)用nativeDestroy(long ptr)方法
        nativeDestroy(mPtr);
        mPtr = 0;
    }
}

nativeDestroy(long ptr)方法通過JNI調(diào)用android_os_MessageQueue_nativeDestroy(JNIEnv env, jclass clazz, jlong ptr)*函數(shù)骨坑,該函數(shù)源碼如下所示:

// frameworks/base/core/jni/android_os_MessageQueue.cpp
static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    // 調(diào)用RefBase類decStrong(const void* id)函數(shù)
    nativeMessageQueue->decStrong(env);
}

NativeMessageQueue類繼承RefBase類撼嗓,這里調(diào)用了RefBase類的decStrong(const void id)*函數(shù),源碼如下所示:

// system/core/libutils/RefBase.cpp
void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    // 刪除強(qiáng)引用
    refs->removeStrongRef(id);
    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
#if PRINT_REFS
    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    LOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "decStrong() called on %p too many times",
            refs);
    if (c == 1) {
        std::atomic_thread_fence(std::memory_order_acquire);
        refs->mBase->onLastStrongRef(id);
        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            delete this;
            // 析構(gòu)函數(shù)在這種情況下不會刪除引用
        }
    }
    // 刪除弱引用
    refs->decWeak(id);
}

小結(jié)

nativeDestroy(long ptr)方法執(zhí)行如下邏輯:

  • 調(diào)用RefBase::decStrong(const void id)函數(shù)減少對象的引用計數(shù)*欢唾。
  • 當(dāng)引用計數(shù)0的時候且警,就刪除NativeMessageQueue對象。

nativePollOnce(long ptr, int timeoutMillis)

nativePollOnce(long ptr, int timeoutMillis)方法是在MessageQueue類的next()方法調(diào)用礁遣,源碼如下所示:

// MessageQueue.java
@UnsupportedAppUsage
Message next() {
    // 省略部分代碼
    for (;;) {
        // 省略部分代碼

        nativePollOnce(ptr, nextPollTimeoutMillis);

        // 省略部分代碼
    }
}

nativePollOnce(long ptr, int timeoutMillis)方法通過JNI調(diào)用android_os_MessageQueue_nativePollOnce(JNIEnv env, jobject obj,
jlong ptr, jint timeoutMillis)
*函數(shù)斑芜,該函數(shù)的源碼如下所示:

// frameworks/base/core/jni/android_os_MessageQueue.cpp
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
        jlong ptr, jint timeoutMillis) {
    // 將Java層的mPtr傳遞到該函數(shù),然后將其強(qiáng)轉(zhuǎn)成NativeMessageQueue
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    // 調(diào)用NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis)函數(shù)
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}

NativeMessageQueue::pollOnce(JNIEnv env, jobject pollObj, int timeoutMillis)*函數(shù)的源碼如下所示:

// frameworks/base/core/jni/android_os_MessageQueue.cpp
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    mPollEnv = env;
    mPollObj = pollObj;
    // 調(diào)用pollOnce(int timeoutMillis)函數(shù)
    mLooper->pollOnce(timeoutMillis);
    mPollObj = NULL;
    mPollEnv = NULL;

    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}

pollOnce(int timeoutMillis)函數(shù)的源碼如下所示:

// system/core/libutils/include/utils/Looper.h
inline int pollOnce(int timeoutMillis) {
    // 調(diào)用Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData)函數(shù)
    return pollOnce(timeoutMillis, nullptr, nullptr, nullptr);
}

Looper::pollOnce(int timeoutMillis, int outFd, int outEvents, void* outData)*函數(shù)的源碼如下所示:

// system/core/libutils/Looper.cpp
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    // 循環(huán)執(zhí)行
    for (;;) {
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {
                // 如果ident大于等于0祟霍,說明沒有callback杏头,因?yàn)镻OLL_CALLBACK等于-2,就執(zhí)行以下邏輯
                // 處理沒有callback的response事件
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE
                ALOGD("%p ~ pollOnce - returning signalled identifier %d: "
                        "fd=%d, events=0x%x, data=%p",
                        this, ident, fd, events, data);
#endif
                if (outFd != nullptr) *outFd = fd;
                if (outEvents != nullptr) *outEvents = events;
                if (outData != nullptr) *outData = data;
                return ident;
            }
        }

        if (result != 0) {
#if DEBUG_POLL_AND_WAKE
            ALOGD("%p ~ pollOnce - returning result %d", this, result);
#endif
            if (outFd != nullptr) *outFd = 0;
            if (outEvents != nullptr) *outEvents = 0;
            if (outData != nullptr) *outData = nullptr;
            return result;
        }

        // 調(diào)用Looper::pollInner(int timeoutMillis)函數(shù)
        result = pollInner(timeoutMillis);
    }
}

參數(shù)如下所示:

  • timeoutMillis超時時間沸呐。
  • outFd:發(fā)生事件的文字描述符醇王。
  • outEvents:當(dāng)前outFd上發(fā)生的事件,類型如下所示:
    • EVENT_INPUT可讀
    • EVENT_OUTPUT可寫
    • EVENT_ERROR錯誤
    • EVENT_HANGUP中斷
  • outData上下文數(shù)據(jù)崭添。

Looper::pollInner(int timeoutMillis)函數(shù)的源碼如下所示:

// system/core/libutils/Looper.cpp
int Looper::pollInner(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
#endif

    // 根據(jù)下一條消息到期的時間調(diào)整超時時間
    if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
        if (messageTimeoutMillis >= 0
                && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
            timeoutMillis = messageTimeoutMillis;
        }
#if DEBUG_POLL_AND_WAKE
        ALOGD("%p ~ pollOnce - next message in %" PRId64 "ns, adjusted timeout: timeoutMillis=%d",
                this, mNextMessageUptime - now, timeoutMillis);
#endif
    }

    // poll
    int result = POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0;

    // 即將處于空閑狀態(tài)
    mPolling = true;

    // 文件描述符的最大數(shù)量是16
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    // 等待事件上報
    int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    // 不再是空閑狀態(tài)
    mPolling = false;

    // 加鎖
    mLock.lock();

    // 如果需要的寓娩,就重新設(shè)置poll
    if (mEpollRebuildRequired) {
        mEpollRebuildRequired = false;
        rebuildEpollLocked();
        goto Done;
    }

    if (eventCount < 0) {
        if (errno == EINTR) {
            goto Done;
        }
        ALOGW("Poll failed with an unexpected error: %s", strerror(errno));
        // 如果epoll的事件數(shù)量小于0,說明發(fā)生錯誤,跳轉(zhuǎn)到Done標(biāo)簽
        result = POLL_ERROR;
        goto Done;
    }

    if (eventCount == 0) {
#if DEBUG_POLL_AND_WAKE
        ALOGD("%p ~ pollOnce - timeout", this);
#endif
        // 如果epoll的事件數(shù)量等于0根暑,說明超時力试,跳轉(zhuǎn)到Done標(biāo)簽
        result = POLL_TIMEOUT;
        goto Done;
    }

    // 循環(huán)執(zhí)行,處理所有事件
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
#endif

    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeEventFd.get()) {
            if (epollEvents & EPOLLIN) {
                // 如果已經(jīng)喚醒排嫌,就讀取并且清空管道數(shù)據(jù)
                awoken();
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
            }
        } else {
            ssize_t requestIndex = mRequests.indexOfKey(fd);
            if (requestIndex >= 0) {
                int events = 0;
                if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
                if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
                if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
                if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
                // 處理request畸裳,并且生成對應(yīng)的response對象,同時push到響應(yīng)數(shù)據(jù)
                pushResponse(events, mRequests.valueAt(requestIndex));
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
                        "no longer registered.", epollEvents, fd);
            }
        }
    }
Done: ;

    // 處理Native層的Message淳地,調(diào)用相應(yīng)的回調(diào)方法
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
        if (messageEnvelope.uptime <= now) {
            // 從列表中刪除信封怖糊,持有Handler的強(qiáng)引用,直到handleMessage方法調(diào)用結(jié)束颇象,然后刪除它伍伤,這樣處理器就可以在我們重新獲得鎖之前被刪除
            {
                // 獲得Handler
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();

#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
                ALOGD("%p ~ pollOnce - sending message: handler=%p, what=%d",
                        this, handler.get(), message.what);
#endif
                handler->handleMessage(message);
            }

            // 釋放Handler
            mLock.lock();
            mSendingMessage = false;
            result = POLL_CALLBACK;
        } else {
            // 消息隊(duì)列中最后一條消息決定下一次喚醒的時間
            mNextMessageUptime = messageEnvelope.uptime;
            break;
        }
    }

    // 釋放鎖
    mLock.unlock();

    // 調(diào)用所有response的回調(diào)方法
    for (size_t i = 0; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
            ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
                    this, response.request.callback.get(), fd, events, data);
#endif
            // 調(diào)用回調(diào)方法,要注意的是遣钳,在函數(shù)返回之前扰魂,文件描述符可能被回調(diào)關(guān)閉(甚至可能被重用),因此隨后刪除文件描述符時蕴茴,我們需要稍微小心一點(diǎn)
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd, response.request.seq);
            }

            // 迅速清除response結(jié)構(gòu)中回調(diào)引用劝评,因?yàn)橹钡较乱淮屋喸儾艜宄齬esponse本身
            response.request.callback.clear();
            result = POLL_CALLBACK;
        }
    }
    return result;
}

Looper::pollInner(int timeoutMillis)函數(shù)的返回值有如下所示:

  • POLL_WAKE:表示由wake()觸發(fā),也就是pipe寫端write事件觸發(fā)倦淀。
  • POLL_CALLBACK:表示由某個被監(jiān)聽的文件描述符被觸發(fā)蒋畜。
  • POLL_TIMEOUT:表示等待超時
  • POLL_ERROR:表示等待期間發(fā)生錯誤撞叽。

Looper::awoken()函數(shù)的源碼如下所示:

// system/core/libutils/Looper.cpp
void Looper::awoken() {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ awoken", this);
#endif

    uint64_t counter;
    // 不斷讀取管道數(shù)據(jù)姻成,清空管道內(nèi)容
    TEMP_FAILURE_RETRY(read(mWakeEventFd.get(), &counter, sizeof(uint64_t)));
}

小結(jié)

nativePollOnce(long ptr, int timeoutMillis)方法執(zhí)行以下邏輯:

  • 調(diào)用Looper::pollOnce(int timeoutMillis, int outFd, int outEvents, void* outData)函數(shù),在空閑狀態(tài)下停留在epoll_wait(int fd, struct epoll_event events, int max_events, int timeout)函數(shù)愿棋,目的是等待事件的發(fā)生或者超時**科展。

nativeWake(long ptr)

nativeWake(long ptr)方法的作用是喚醒線程,在MessageQueue類的enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)方法和quit()方法都有調(diào)用該方法初斑。

android_os_MessageQueue_nativeWake(JNIEnv env, jclass clazz, jlong ptr)*函數(shù)的源碼如下所示:

// 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);
    // 調(diào)用NativeMessageQueue::wake()函數(shù)
    nativeMessageQueue->wake();
}

NativeMessageQueue::wake()函數(shù)的源碼如下所示:

// frameworks/base/core/jni/android_os_MessageQueue.cpp
void NativeMessageQueue::wake() {
    // 調(diào)用Looper::wake()函數(shù)
    mLooper->wake();
}

Looper::wake()函數(shù)的源碼如下所示:

// system/core/libutils/Looper.cpp
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ wake", this);
#endif

    uint64_t inc = 1;
    // 向管道m(xù)WakeEventFd寫入字符
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
    if (nWrite != sizeof(uint64_t)) {
        if (errno != EAGAIN) {
            LOG_ALWAYS_FATAL("Could not write wake signal to fd %d (returned %zd): %s",
                             mWakeEventFd.get(), nWrite, strerror(errno));
        }
    }
}

小結(jié)

nativeWake(long ptr)執(zhí)行如下邏輯:

  • 調(diào)用Looper::wake()函數(shù)辛润,向管道m(xù)WakeEventFd寫入字符。

Looper

Looper用于為線程運(yùn)行消息循環(huán)见秤,從MessageQueue(消息隊(duì)列)中取出消息砂竖,然后分發(fā)給Message(消息)對應(yīng)的宿主Handler。默認(rèn)情況下鹃答,線程沒有與之關(guān)聯(lián)的消息循環(huán)乎澄,要創(chuàng)建一個循環(huán),就在運(yùn)行循環(huán)的線程中調(diào)用prepare()方法测摔,然后調(diào)用loop()方法讓它處理消息置济,直到循環(huán)停止解恰。

要注意的是,每一個線程只有存在一個Looper對象浙于。

Java層

成員變量

Looper類相關(guān)的成員變量护盈,源碼如下所示:

// Looper.java
// 標(biāo)簽
private static final String TAG = "Looper";

// 使用ThreadLocal存儲Looper對象,使每個線程都能訪問自己的一份Looper對象的變量副本
@UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
// 主線程的Looper對象
@UnsupportedAppUsage
private static Looper sMainLooper;
// 當(dāng)前Looper對象的觀察者
private static Observer sObserver;

// 當(dāng)前Looper對象的消息隊(duì)列
@UnsupportedAppUsage
final MessageQueue mQueue;
// 當(dāng)前Looper對象的所在的線程
final Thread mThread;

// 打印文本
@UnsupportedAppUsage
private Printer mLogging;
// 跟蹤標(biāo)記
private long mTraceTag;

// 如果消息分發(fā)時間超過該時間羞酗,就會顯示警告日志
private long mSlowDispatchThresholdMs;

// 如果消息傳遞時間超過該時間腐宋,就會顯示警告日志
private long mSlowDeliveryThresholdMs;

prepare()

prepare()方法的作用是在當(dāng)前線程初始化Looper對象,相關(guān)的源碼如下所示:

// Looper.java
// 在普通線程中初始化Looper對象
public static void prepare() {
    // 初始化一個可以退出Looper的Looper對象
    prepare(true);
}

// 私有的Looper對象初始化方法檀轨,形式參數(shù)quitAllowed為是否退出Looper
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        // 每個線程只有一個Looper對象胸竞,否則就拋出RuntimeException異常
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    // 將Looper對象存儲到ThreadLocal對象
    sThreadLocal.set(new Looper(quitAllowed));
}

// 在主線程中初始化Looper對象,要注意的是参萄,我們不需要自己手動調(diào)用這個方法來在主線程中初始化Looper對象卫枝,因?yàn)樗呀?jīng)被Android系統(tǒng)創(chuàng)建
public static void prepareMainLooper() {
    // 初始化一個不可以退出Looper的Looper對象
    prepare(false);
    // 取Looper的Class對象作為鎖對象
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            // 如果已經(jīng)在主線程創(chuàng)建過Looper對象,就拋出IllegalStateException異常
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        // 調(diào)用myLooper()方法拿到與當(dāng)前線程關(guān)聯(lián)的Looper對象讹挎,并且賦值給成員變量sMainLooper
        sMainLooper = myLooper();
    }
}

// 返回與當(dāng)前線程關(guān)聯(lián)的Looper對象
public static @Nullable Looper myLooper() {
    // 從ThreadLocal對象中取出與當(dāng)前線程關(guān)聯(lián)的Looper對象
    return sThreadLocal.get();
}

// 返回與當(dāng)前線程關(guān)聯(lián)的Looper對象對應(yīng)的MessageQueue對象
public static @NonNull MessageQueue myQueue() {
    return myLooper().mQueue;
}

loop()

loop()方法的作用是在當(dāng)前線程中運(yùn)行消息隊(duì)列校赤,源碼如下所示:

// Looper.java
public static void loop() {
    // 與當(dāng)前線程關(guān)聯(lián)的Looper對象
    final Looper me = myLooper();
    if (me == null) {
        // 如果沒有初始化Looper對象,就拋出RuntimeException異常
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    // 與當(dāng)前線程關(guān)聯(lián)的Looper對象對應(yīng)的消息隊(duì)列
    final MessageQueue queue = me.mQueue;

    // 得到當(dāng)前線程的唯一標(biāo)識(uid和pid)淤袜,作用是下面每次循環(huán)都會判斷線程有沒有被切換
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    // 允許使用系統(tǒng)屬性覆蓋閾值痒谴,例如: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;

    // 循環(huán)執(zhí)行
    for (;;) {
        // 從消息隊(duì)列中取出消息衰伯,這有可能會阻塞線程
        Message msg = queue.next();
        if (msg == null) {
            // 如果消息是空铡羡,證明消息隊(duì)列已經(jīng)退出,結(jié)束循環(huán)意鲸,結(jié)束方法
            return;
        }

        // 打印日志
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }
        // 確保觀察者在處理事務(wù)的時候不會改變
        final Observer observer = sObserver;

        // 性能分析相關(guān)的邏輯
        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;
        Object token = null;
        if (observer != null) {
            // 如果觀察者不為空烦周,就調(diào)用觀察者的messageDispatchStarting()方法拿到token,它會在發(fā)送消息之前調(diào)用
            token = observer.messageDispatchStarting();
        }
        long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
        try {
            // 調(diào)用宿主Handler的dispatchMessage(Message msg)方法怎顾,將消息分發(fā)給宿主Handler
            msg.target.dispatchMessage(msg);
            if (observer != null) {
                // 如果觀察者不為空读慎,就調(diào)用觀察者的messageDispatched(Object token, Message msg)方法,它會在消息被處理的時候調(diào)用
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } catch (Exception exception) {
            if (observer != null) {
                // 如果發(fā)生異常槐雾,并且觀察者不為空夭委,就調(diào)用觀察者的dispatchingThrewException(Object token, Message msg, Exception exception)方法,它會在處理消息時引發(fā)異常的時候調(diào)用
                observer.dispatchingThrewException(token, msg, exception);
            }
            throw exception;
        } finally {
            // ThreadLocalWorkSource是用于跟蹤是誰觸發(fā)了這個線程上當(dāng)前執(zhí)行的工作募强,調(diào)用store(long token)方法株灸,使用提供的令牌恢復(fù)狀態(tài)
            ThreadLocalWorkSource.restore(origWorkSource);
            if (traceTag != 0) {
                // 性能分析相關(guān)的邏輯
                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) {
            // 如果消息分發(fā)時間超過時間擎值,就會顯示警告日志
            showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
        }

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

        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            // 如果本次循環(huán)中的線程和開始調(diào)用的線程不一樣慌烧,就打印日志
            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);
        }

        // 消息分發(fā)完畢,將消息回收到消息池中
        msg.recycleUnchecked();
    }
}

quit()

quit()的作用是退出Looper鸠儿,源碼如下所示:

// Looper.java
// 退出Looper屹蚊,要注意的是厕氨,在Looper被要求退出后,任何向消息隊(duì)列發(fā)送消息的嘗試都是將失敗汹粤,例如:sendMessage(Message msg)方法返回false
public void quit() {
    mQueue.quit(false);
}

// 安全退出Looper命斧,要注意的是,在Looper被要求退出后嘱兼,任何向消息隊(duì)列發(fā)送消息的嘗試都是將失敗冯丙,例如:sendMessage(Message msg)方法返回false
public void quitSafely() {
    mQueue.quit(true);
}

調(diào)用到MessageQueuequit(boolean safe)方法,這個方法前面解釋過了遭京,這里不再贅述胃惜。

Native層

Looper.h文件中定義了三個結(jié)構(gòu)體,分別是請求(Request)結(jié)構(gòu)體哪雕、響應(yīng)(Response)結(jié)構(gòu)體信封(MessageEnvelope)結(jié)構(gòu)體船殉,源碼如下所示:

// system/core/libutils/include/utils/Looper.h
// 請求結(jié)構(gòu)體
struct Request {
    // 文件描述符
    int fd;
    // 當(dāng)前事件發(fā)生的標(biāo)識符,數(shù)值大于等于0或者是POLL_CALLBACK(-2)
    int ident;
    // 要監(jiān)聽的文件類型斯嚎,默認(rèn)是EVENT_INPUT利虫,前面解釋過,這里不再贅述
    int events;
    int seq;
    // 當(dāng)有事件發(fā)生時堡僻,會回調(diào)該callback函數(shù)
    sp<LooperCallback> callback;
    // 文件描述符里的數(shù)據(jù)
    void* data;

    void initEventItem(struct epoll_event* eventItem) const;
};

// 響應(yīng)結(jié)構(gòu)體
struct Response {
    // 文件類型糠惫,默認(rèn)是EVENT_INPUT,前面解釋過钉疫,這里不再贅述
    int events;
    // Request對象
    Request request;
};

// 信封結(jié)構(gòu)體
struct MessageEnvelope {
    MessageEnvelope() : uptime(0) { }

    MessageEnvelope(nsecs_t u, sp<MessageHandler> h, const Message& m)
        : uptime(u), handler(std::move(h)), message(m) {}

    // 發(fā)信時間
    nsecs_t uptime;
    // 信封接受者
    sp<MessageHandler> handler;
    // 信封內(nèi)容
    Message message;
};

構(gòu)造函數(shù)

Looper.cpp文件部分的源碼如下所示:

// system/core/libutils/Looper.cpp
// 每次迭代檢索輪詢事件所需的文件描述符的最大數(shù)量是16
static const int EPOLL_MAX_EVENTS = 16;

// Looper的構(gòu)造函數(shù)
Looper::Looper(bool allowNonCallbacks)
    : mAllowNonCallbacks(allowNonCallbacks),
      mSendingMessage(false),
      mPolling(false),
      mEpollRebuildRequired(false),
      mNextRequestSeq(0),
      mResponseIndex(0),
      mNextMessageUptime(LLONG_MAX) {
    // eventfd(unsigned int __initial_value, int __flags)函數(shù)用來創(chuàng)建一個事件對象硼讽,它返回一個文件描述符來代表這個事件對象,我們可以使用它來調(diào)用對象牲阁,這里是創(chuàng)建一個喚醒事件的文件描述符
    mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
    LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));

    // AutoMutex _l函數(shù)的作用是對mLock加鎖固阁,執(zhí)行完成后自動釋放鎖,它利用了C++的構(gòu)造函數(shù)和析構(gòu)函數(shù)的自動加鎖和自動釋放鎖
    AutoMutex _l(mLock);
    // 重建mPoll事件
    rebuildEpollLocked();
}

Looper構(gòu)造函數(shù)里執(zhí)行的邏輯前面解釋過了,這里就不再贅述。

sendMessage開頭系列函數(shù)

源碼如下所示:

// system/core/libutils/Looper.cpp
void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
    // 獲得系統(tǒng)時間
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    // 調(diào)用Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
        const Message& message)函數(shù)
    sendMessageAtTime(now, handler, message);
}

void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
        const Message& message) {
    // 獲得系統(tǒng)時間
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    // 調(diào)用Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
        const Message& message)函數(shù)
    sendMessageAtTime(now + uptimeDelay, handler, message);
}

void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
        const Message& message) {
#if DEBUG_CALLBACKS
    ALOGD("%p ~ sendMessageAtTime - uptime=%" PRId64 ", handler=%p, what=%d",
            this, uptime, handler.get(), message.what);
#endif

    size_t i = 0;
    {
        // 加鎖
        AutoMutex _l(mLock);

        size_t messageCount = mMessageEnvelopes.size();
        while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
            // 按著時間順序統(tǒng)計索引i
            i += 1;
        }

        // 創(chuàng)建信封瘾晃,并且傳入對應(yīng)的參數(shù)
        MessageEnvelope messageEnvelope(uptime, handler, message);
        // 根據(jù)索引i將信封插入到信封向量(Vector丧裁,  它是一個封裝了動態(tài)大小數(shù)組的順序容器)
        mMessageEnvelopes.insertAt(messageEnvelope, i, 1);

        if (mSendingMessage) {
            // 如果當(dāng)前正在發(fā)送消息,就不再調(diào)用wake()函數(shù)喚醒poll循環(huán),結(jié)束函數(shù)
            return;
        }
    }
    // 釋放鎖

    if (i == 0) {
        // 如果i等于0,說明該消息插入到信封向量的頭部,調(diào)用wake()函數(shù)喚醒poll循環(huán)
        wake();
    }
}

回調(diào)類

LooperCallback類的源碼如下所示:

// system/core/libutils/include/utils/Looper.h
class LooperCallback : public virtual RefBase {
protected:
    // LooperCallback()函數(shù)是虛析構(gòu)函數(shù)
    virtual ~LooperCallback();

public:
    // 處理給定的文件描述符的poll事件况褪,它提供與之關(guān)聯(lián)的文件描述符,被觸發(fā)的poll事件的位掩碼(通常是EVENT_INPUT)和最初提供的數(shù)據(jù)指針
    virtual int handleEvent(int fd, int events, void* data) = 0;
};

SimpleLooperCallback類繼承LooperCallback類霎挟,SimpleLooperCallback類的源碼如下所示:

// system/core/libutils/include/utils/Looper.h
class SimpleLooperCallback : public LooperCallback {
protected:
    // SimpleLooperCallback()是虛析構(gòu)函數(shù)
    virtual ~SimpleLooperCallback();

public:
    SimpleLooperCallback(Looper_callbackFunc callback);
    // handleEvent(int fd, int events, void* data)是虛函數(shù)
    virtual int handleEvent(int fd, int events, void* data);

private:
    // 回調(diào)函數(shù)
    Looper_callbackFunc mCallback;
};

看下handleEvent(int fd, int events, void data)*函數(shù)窝剖,源碼如下所示:

// system/core/libutils/Looper.cpp
int SimpleLooperCallback::handleEvent(int fd, int events, void* data) {
    // 調(diào)用回調(diào)函數(shù)
    return mCallback(fd, events, data);
}

Handler

Handler用于處理消息向消息池發(fā)送消息事件處理消息事件酥夭。

Java層

構(gòu)造方法

看下Handler構(gòu)造方法赐纱,源碼如下所示:

// Handler.java
// 默認(rèn)構(gòu)造方法脊奋,用于將該Handler與當(dāng)前線程的Looper對象相關(guān)聯(lián)
public Handler() {
    this(null, false);
}

// 構(gòu)造方法,用于將該Handler與當(dāng)前線程的Looper對象相關(guān)聯(lián)疙描,并且接受一個可以處理消息的回調(diào)接口诚隙,參數(shù)callback可以為空
public Handler(@Nullable Callback callback) {
    this(callback, false);
}

// 構(gòu)造方法,用于將該Handler與傳遞進(jìn)來的Looper對象相關(guān)聯(lián)起胰,參數(shù)looper不可為空
public Handler(@NonNull Looper looper) {
    this(looper, null, false);
}

// 構(gòu)造方法久又,用于將該Handler與傳遞進(jìn)來的Looper對象相關(guān)聯(lián),并且接受一個可以處理消息的回調(diào)接口效五,參數(shù)looper不可為空地消,參數(shù)callback可為空
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
    this(looper, callback, false);
}

// 構(gòu)造方法,用于將該Handler與當(dāng)前線程的Looper對象相關(guān)聯(lián)畏妖,并且設(shè)置Handler是否應(yīng)該是異步脉执,Handler在默認(rèn)情況下是同步的,調(diào)用該方法可以構(gòu)造異步的Handler戒劫,要注意的是半夷,該方法不支持外部應(yīng)用使用
public Handler(boolean async) {
    this(null, async);
}

上面的構(gòu)造方法最終會調(diào)用以下兩個方法,源碼如下所示:

// Handler.java
public Handler(@Nullable Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        // 如果存在內(nèi)存泄漏的風(fēng)險迅细,就執(zhí)行以下邏輯
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            // 如果是匿名類巫橄,或者是內(nèi)部類,或者是本地類茵典,都要申明成靜態(tài)湘换,否則就會打印出警告,警告有可能會出現(xiàn)內(nèi)存泄漏
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }

    // 得到當(dāng)前線程的Looper對象
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        // 如果當(dāng)前線程的Looper對象為空敬尺,也就是Looper還沒初始化枚尼,就拋出RuntimeException異常
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    // 得到當(dāng)前線程的Looper對象所對應(yīng)的MessageQueue
    mQueue = mLooper.mQueue;
    // 將形式參數(shù)callback賦值給給成員變量mCallback
    mCallback = callback;
    // 將形式參數(shù)asyn賦值給成員變量mAsynchronous
    mAsynchronous = async;
}

// 使用傳遞進(jìn)來的Looper對象,而不是使用默認(rèn)的砂吞,并且接受一個處理消息的回調(diào)接口,還要設(shè)置Handler是否應(yīng)該是異步的崎溃,需要注意的是蜻直,該方法不支持外部應(yīng)用使用
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

發(fā)送消息

發(fā)送消息主要分為兩類方法:

  • post開頭的方法
  • sendMessage開頭的方法

看下相關(guān)的源碼,源碼如下所示:

// Handler.java
// 將傳遞進(jìn)來的Runnable添加到消息隊(duì)列的尾部袁串,該Runnable將在附加在該Handler的線程上運(yùn)行
public final boolean post(@NonNull Runnable r) {
   return  sendMessageDelayed(getPostMessage(r), 0);
}

// 將傳遞進(jìn)來的Runnable添加到消息隊(duì)列的尾部概而,并在uptimeMillis時間內(nèi)運(yùn)行,該Runnable將在附加在該Handler的線程上運(yùn)行
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
    return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}

// 將傳遞進(jìn)來的Runnable添加到消息隊(duì)列的尾部囱修,并在uptimeMillis時間內(nèi)運(yùn)行赎瑰,token是個令牌,它為了在調(diào)用removeCallbacksAndMessages(Object token)方法可以刪除消息隊(duì)列中對應(yīng)的消息破镰,該Runnable將在附加在該Handler的線程上運(yùn)行
public final boolean postAtTime(
        @NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
    return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}

// 將傳遞進(jìn)來的Runnable添加到消息隊(duì)列的尾部餐曼,并在delayMillis的時間后運(yùn)行压储,該Runnable將在附加在該Handler的線程上運(yùn)行
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
    return sendMessageDelayed(getPostMessage(r), delayMillis);
}

// 將傳遞進(jìn)來的Runnable添加到消息隊(duì)列的尾部,并在delayMillis的時間后運(yùn)行源譬,同時設(shè)置該消息的消息類別what集惋,該Runnable將在附加在該Handler的線程上運(yùn)行,要注意的是踩娘,該方法不支持外部應(yīng)用調(diào)用
public final boolean postDelayed(Runnable r, int what, long delayMillis) {
    return sendMessageDelayed(getPostMessage(r).setWhat(what), delayMillis);
}

// 將傳遞進(jìn)來的Runnable添加到消息隊(duì)列的尾部刮刑,并在delayMillis的時間后運(yùn)行,token是個令牌养渴,它為了在調(diào)用removeCallbacksAndMessages(Object token)方法可以刪除消息隊(duì)列中對應(yīng)的消息雷绢,該Runnable將在附加在該Handler的線程上運(yùn)行
public final boolean postDelayed(
        @NonNull Runnable r, @Nullable Object token, long delayMillis) {
    return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}

// 將傳遞進(jìn)來的Runnable添加到消息隊(duì)列的頭部,該Runnable將在附加在該Handler的線程上運(yùn)行
public final boolean postAtFrontOfQueue(@NonNull Runnable r) {
    return sendMessageAtFrontOfQueue(getPostMessage(r));
}

// 將傳遞進(jìn)來的Message添加到消息隊(duì)列的尾部
public final boolean sendMessage(@NonNull Message msg) {
    return sendMessageDelayed(msg, 0);
}

// 添加一條空的普通消息到消息隊(duì)列的尾部理卑,并且設(shè)置該消息的消息類別what
public final boolean sendEmptyMessage(int what)
{
    return sendEmptyMessageDelayed(what, 0);
}

// 添加一條空的延時delayMillis的普通消息到消息隊(duì)列的尾部习寸,并且設(shè)置該消息的消息類別what
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}

// 添加一條空的uptimeMillis時間內(nèi)運(yùn)行的普通消息到消息隊(duì)列的尾部,并且設(shè)置該消息的消息類別what
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageAtTime(msg, uptimeMillis);
}

// 添加一條延時delayMillis的普通消息到消息隊(duì)列的尾部
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

// 添加一條uptimeMillis時間內(nèi)運(yùn)行的普通消息到消息隊(duì)列的尾部
public boolean sendMessageAtTime(@NonNull 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);
}

// 添加一條普通消息到消息隊(duì)列的頭部
public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
    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, 0);
}

// 如果在該Handler對應(yīng)的同一個線程上調(diào)用該消息傻工,就同步執(zhí)行該消息霞溪,否則,調(diào)用sendMessage(Message msg)方法將其添加到消息隊(duì)列中中捆,如果消息成功運(yùn)行或者成功添加到消息隊(duì)列中鸯匹,就返回true,否則泄伪,就返回false殴蓬,這通常是因?yàn)樘幚硐⒌腖ooper退出
public final boolean executeOrSendMessage(@NonNull Message msg) {
    if (mLooper == Looper.myLooper()) {
        dispatchMessage(msg);
        return true;
    }
    return sendMessage(msg);
}

可以發(fā)現(xiàn)post開頭的方法都調(diào)用getPostMessage(Runnable r)方法或者getPostMessage(Runnable r, Object token)方法,其實(shí)post開頭的方法本質(zhì)上和sendMessage開頭的方法一樣的蟋滴,都是添加一條普通消息到消息隊(duì)列中染厅,源碼如下所示:

// Handler.java
// 從消息池中取出消息,并且設(shè)置該消息的callback為傳進(jìn)來的Runnable津函,最后返回該消息
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

// 從消息池中取出消息肖粮,并且設(shè)置該消息的obj為傳遞進(jìn)來的令牌token,callback為傳遞進(jìn)來的Runnable尔苦,最后返回該消息
@UnsupportedAppUsage
private static Message getPostMessage(Runnable r, Object token) {
    Message m = Message.obtain();
    m.obj = token;
    m.callback = r;
    return m;
}

以上發(fā)送消息的方法最后會調(diào)用sendMessageAtTime(Message msg, long uptimeMillis)方法或者sendMessageAtFrontOfQueue(Message msg)方法涩馆,然后這兩個方法會調(diào)用enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)方法,最后這個方法會調(diào)用MessageQueueenqueueMessage(Message msg, long when)方法允坚,前面提到過了魂那,這里就不再贅述了,源碼如下所示:

// Handler.java
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
    // 將消息的接受者設(shè)置為本身
    msg.target = this;
    // 設(shè)置消息進(jìn)入隊(duì)列的uid
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    if (mAsynchronous) {
        // 如果是異步的稠项,就設(shè)置消息為異步消息
        msg.setAsynchronous(true);
    }
    // 調(diào)用MessageQueue的enqueueMessage(Message msg, long when)方法
    return queue.enqueueMessage(msg, uptimeMillis);
}

dispatchMessage(Message msg)

dispatchMessage(Message msg)方法的作用是分發(fā)消息涯雅,源碼如下所示:

// Handler.java
public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        // 如果msg.callback不為空,也就是通過post開頭的方法添加消息到消息隊(duì)列中的展运,就調(diào)用handleCallback(Message message)方法
        handleCallback(msg);
    } else {
        // 如果msg.callback為空活逆,也就是通過sendMessage開頭的方法添加消息到消息隊(duì)列中精刷,就執(zhí)行以下邏輯
        if (mCallback != null) {
            // 如果成員變量mCallback不為空,說明Handler設(shè)置了Callback划乖,就調(diào)用mCallback的handleMessage(Message msg)方法
            if (mCallback.handleMessage(msg)) {
                // 如果handleMessage(Message msg)方法返回true贬养,就說明該消息已經(jīng)被攔截,不需要再進(jìn)一步處理琴庵,結(jié)束方法
                return;
            }
        }
        // 如果handleMessage(Message msg)方法返回false误算,就說明該消息沒被攔截,需要進(jìn)一步處理迷殿,調(diào)用handleMessage(Message msg)方法
        handleMessage(msg);
    }
}

如果是通過post開頭的方法添加消息消息隊(duì)列中儿礼,最后會調(diào)用handleCallback(Message message)方法,源碼如下所示:

// Handler.java
private static void handleCallback(Message message) {
    // 調(diào)用消息的Runnable的run()方法
    message.callback.run();
}

如果是通過sendMessage開頭的方法添加消息消息隊(duì)列中庆寺,最后會調(diào)用Handler的內(nèi)部接口Callback的handleMessage(Message msg)方法或者handleMessage(Message msg)方法蚊夫,這兩個方法需要開發(fā)者自己去實(shí)現(xiàn),源碼如下所示:

// Handler.java
public interface Callback {
    // 該方法需要開發(fā)者自己去實(shí)現(xiàn)懦尝,如果該方法返回true知纷,就說明該消息已經(jīng)被攔截;如果該方法返回false陵霉,就說明該消息沒被攔截琅轧,需要進(jìn)一步處理
    boolean handleMessage(@NonNull Message msg);
}

// 該方法需要開發(fā)者自己去實(shí)現(xiàn)
public void handleMessage(@NonNull Message msg) {
}

處理Message的優(yōu)先級

處理Message優(yōu)先級從上到下踊挠,優(yōu)先級從低到高乍桂,如下所示:

  • Handler的handleMessage(Message msg)方法:通過sendMessage開頭的方法添加Message(消息)MessageQueue(消息隊(duì)列)中。
  • Handler的內(nèi)部接口Callback的handleMessage(Message msg)方法:通過構(gòu)造方法設(shè)置Handler的內(nèi)部接口Callback效床。
  • Message的成員變量callback(Runnable)的run()方法:通過post開頭的方法添加MessageMessageQueue(消息隊(duì)列)中睹酌。

obtainMessage系列方法

obtainMessage系列方法的作用是從消息池中取出消息,源碼如下所示:

// Handler.java
// 從消息池中取出消息
@NonNull
public final Message obtainMessage()
{
    return Message.obtain(this);
}

// 從消息池中取出消息類別是what的消息
@NonNull
public final Message obtainMessage(int what)
{
    return Message.obtain(this, what);
}

// 從消息池中取出消息類別是what剩檀,并且消息內(nèi)容是obj的消息
@NonNull
public final Message obtainMessage(int what, @Nullable Object obj) {
    return Message.obtain(this, what, obj);
}

// 從消息池中取出消息類別是what憋沿,并且?guī)в袇?shù)arg1和參數(shù)arg2的消息
@NonNull
public final Message obtainMessage(int what, int arg1, int arg2)
{
    return Message.obtain(this, what, arg1, arg2);
}

// 從消息池中取出消息類別是what,并且?guī)в袇?shù)arg1和參數(shù)arg2谨朝,同時消息內(nèi)容是obj的消息
@NonNull
public final Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
    return Message.obtain(this, what, arg1, arg2, obj);
}

以上方法最后都是調(diào)用了Message類obtain系列方法卤妒,它們的作用是從消息池中返回一個新的消息對象避免重新分配新的消息對象字币,這些系列的方法前面解釋過,這里就不再贅述共缕。

刪除消息

刪除消息分為兩類方法

  • removeCallbacks系列方法
  • removeMessages系列方法

源碼如下所示:

// Handler.java
// 刪除消息隊(duì)列中的Runnable普通消息
public final void removeCallbacks(@NonNull Runnable r) {
    mQueue.removeMessages(this, r, null);
}

// 刪除消息隊(duì)列中帶有令牌token的Runnable普通消息
public final void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
    mQueue.removeMessages(this, r, token);
}

// 刪除消息隊(duì)列中消息類別是what的普通消息
public final void removeMessages(int what) {
    mQueue.removeMessages(this, what, null);
}

// 刪除消息隊(duì)列中消息類別是what洗出,消息內(nèi)容是object的普通消息
public final void removeMessages(int what, @Nullable Object object) {
    mQueue.removeMessages(this, what, object);
}

// 刪除消息隊(duì)列中所有帶有令牌token的普通消息,要注意的是图谷,如果形式參數(shù)token傳遞的是空翩活,就會刪除消息隊(duì)列中所有普通消息
public final void removeCallbacksAndMessages(@Nullable Object token) {
    mQueue.removeCallbacksAndMessages(this, token);
}

可以發(fā)現(xiàn)removeCallbacks系列方法最后和removeMessages系列方法是調(diào)用是MessageQueueremoveMessages(Handler h, int what, Object object)方法阱洪,它的作用是刪除消息隊(duì)列中符合條件的普通消息,這個方法前面解釋過菠镇,這里就不再贅述冗荸。

Native層

MessageHandler類的源碼如下所示:

// external/webrtc_legacy/webrtc/base/messagehandler.h
class MessageHandler {
 public:
  // MessageHandler()函數(shù)是虛析構(gòu)函數(shù)
  virtual ~MessageHandler();
  // onMessage(Message* msg)是虛函數(shù)
  virtual void OnMessage(Message* msg) = 0;

 protected:
  MessageHandler() {}

 private:
  RTC_DISALLOW_COPY_AND_ASSIGN(MessageHandler);
};

WeakMessageHandler類繼承MessageHandler類,WeakMessageHandler類的作用是持有對MessageHandler的弱引用的簡單代理利耍,WeakMessageHandler類的源碼如下所示:

// system/core/libutils/include/utils/Looper.h
class WeakMessageHandler : public MessageHandler {
protected:
    // WeakMessageHandler()函數(shù)是虛析構(gòu)函數(shù)
    virtual ~WeakMessageHandler();

public:
    WeakMessageHandler(const wp<MessageHandler>& handler);
    // handleMessage(const Message& message)函數(shù)是虛函數(shù)
    virtual void handleMessage(const Message& message);

private:
    wp<MessageHandler> mHandler;
};

看下handleMessage(const Message& message)函數(shù)蚌本,源碼如下所示:

// system/core/libutils/Looper.cpp
void WeakMessageHandler::handleMessage(const Message& message) {
    sp<MessageHandler> handler = mHandler.promote();
    if (handler != nullptr) {
        // 如果MessageHandler強(qiáng)指針不為空,就調(diào)用MessageHandler的handleMessage(const Message& message)函數(shù)
        handler->handleMessage(message);
    }
}

為什么主線程不會因?yàn)長ooper.loop()方法里的死循環(huán)卡死隘梨?

在解答這個問題之前程癌,先解釋下進(jìn)程線程的概念:

進(jìn)程代碼在數(shù)據(jù)集合上的一次運(yùn)行活動,它是系統(tǒng)進(jìn)行資源分配調(diào)度基本單位轴猎。一個進(jìn)程至少有一個線程嵌莉,線程是進(jìn)程中的實(shí)體線程本身是不會獨(dú)立存在的捻脖,進(jìn)程中多個線程可以共享進(jìn)程的資源(例如:內(nèi)存地址锐峭、文件I/O等)也可以獨(dú)立調(diào)度可婶。

每個應(yīng)用進(jìn)程都從一個名為Zygote的現(xiàn)有進(jìn)程分叉(fork)沿癞。系統(tǒng)啟動并加載通用框架(Framework)代碼和資源(例如:Activity主題背景)時,Zygote進(jìn)程隨之啟動扰肌,為了啟動新的應(yīng)用進(jìn)程抛寝,系統(tǒng)會分叉(fork)Zygote進(jìn)程,然后在新進(jìn)程加載并運(yùn)行引用代碼曙旭,這種方法可以讓框架(Framework)代碼資源分配的大多數(shù)RAM頁面所有應(yīng)用進(jìn)程之間共享盗舰,大多數(shù)情況下,應(yīng)用程序都運(yùn)行在一個進(jìn)程中桂躏,我們也可以在AnroidManifest.xml(清單文件)設(shè)置android:process屬性或者通過native代碼分叉(fork)進(jìn)程創(chuàng)建多個進(jìn)程钻趋,如果想深入了解,可以看下Android的內(nèi)存管理這篇文章剂习。

Java語言統(tǒng)一處理了不同硬件和操作系統(tǒng)平臺線程操作蛮位,一個線程是一個已經(jīng)執(zhí)行start()方法而且還沒結(jié)束的java.lang.Thread類的實(shí)例,其中Thread類的所有關(guān)鍵方法都是本地方法(Native Method)來的鳞绕,這意味著這些方法沒有使用或者無法使用平臺相關(guān)的手段來實(shí)現(xiàn)失仁。

Linux中,進(jìn)程線程除了是否共享資源外们何,并沒有本質(zhì)的區(qū)別萄焦,對于CPU來說就是一段可執(zhí)行的代碼,它們都是一個task_struct結(jié)構(gòu)體CPU采用完全公平調(diào)度器(Completely Fair Scheduler拂封,簡稱CFS)算法茬射,這個算法可以保證每個任務(wù)都盡可能公平地享有CPU時間片

因?yàn)?strong>線程是一段可執(zhí)行的代碼冒签,當(dāng)線程執(zhí)行完成后在抛,也就是可執(zhí)行的代碼執(zhí)行完成后,線程運(yùn)行狀態(tài)就進(jìn)入結(jié)束(Terminated)狀態(tài)萧恕,然后線程就會終止刚梭,對于主線程來說,系統(tǒng)不希望主線程運(yùn)行一段時間后廊鸥,主線程就會終止望浩,那如何讓主線程不被終止呢?可以讓可執(zhí)行的代碼一直執(zhí)行下去惰说,死循環(huán)就是它的實(shí)現(xiàn)方法磨德,它可以保證線程不被終止Binder線程也是使用死循環(huán)這種方法吆视,不斷與Binder驅(qū)動進(jìn)行讀操作或者寫操作典挑,當(dāng)然并非簡單地死循環(huán),這里涉及到Linuxpipe/epoll機(jī)制啦吧,在主線程中您觉,當(dāng)MessageQueue(消息隊(duì)列)沒有Message(消息)時,就會阻塞MessageQueue類的next()方法的nativePollOnce()方法中授滓,這個時候主線程就會釋放CPU資源進(jìn)入休眠狀態(tài)琳水,直到下一個消息到達(dá)或者有事務(wù)發(fā)生通過往pipe管道寫端寫入數(shù)據(jù)來喚醒主線程工作般堆,epoll是一種當(dāng)文件描述符內(nèi)核緩沖區(qū)不是空的時候在孝,發(fā)出可讀信號進(jìn)行通知;當(dāng)寫緩沖區(qū)還沒滿的時候淮摔,發(fā)出可寫信號的進(jìn)行通知的機(jī)制私沮,它是一種I/O多路復(fù)用機(jī)制,可以同時監(jiān)控多個文件描述符和橙;Looper類的loop()方法也不會導(dǎo)致應(yīng)用卡死仔燕,導(dǎo)致卡死的原因是Activity生命周期方法操作時間過長,導(dǎo)致掉幀魔招,甚至導(dǎo)致應(yīng)用無響應(yīng)(ANR)晰搀,所以,主線程在大多數(shù)時候是空閑狀態(tài)的办斑,并不會消耗大量CPU資源厕隧,也不會導(dǎo)致應(yīng)用卡死

總結(jié)

開發(fā)者通過調(diào)用Handlerpost開頭的方法或者sendMessage開頭的方法添加Message(消息)MessageQueue(消息隊(duì)列)中俄周,通過調(diào)用Looperloop()方法不斷從MessageQueue中取出達(dá)到觸發(fā)條件的Message吁讨,然后調(diào)用宿主HandlerdispatchMessage(Message msg)方法,根據(jù)條件判斷峦朗,如果是通過post開頭的方法添加MessageMessageQueue中建丧,就調(diào)用Runnablerun()方法;如果是通過sendMessage開頭的方法添加MessageMessageQueue中波势,先判斷是否通過構(gòu)造方法設(shè)置Handler的內(nèi)部接口Callback翎朱,如果設(shè)置了,就調(diào)用Handler的內(nèi)部接口CallbackhandleMessage(Message msg)方法讓開發(fā)者處理Message尺铣;如果沒有設(shè)置拴曲,就調(diào)用handleMessage(Message msg)方法讓開發(fā)者處理Message,要注意的是凛忿,當(dāng)MessageQueue沒有Message時澈灼,就會處于空閑狀態(tài),調(diào)用MessageQueue的內(nèi)部接口IdleHandlerqueueIdle()方法店溢。

MessageQueue是連接Java層Native層的紐帶叁熔,Java層MessageQueueNative層MessageQueue是通過JNI(Java Native Interface)建立關(guān)聯(lián),Java層可以向MessageQueue添加Message床牧,Native層也可以向MessageQueue添加Message荣回;MessageLooperHandler三個類Java層Native層之間沒有任何關(guān)聯(lián)戈咳,它們都在各自層實(shí)現(xiàn)相似的邏輯心软,彼此是獨(dú)立的Native層NativeMessageQueue類繼承Native層MessageQueue類著蛙,Native層WeakMessageHandler類繼承MessageHandler類删铃。

要注意的是,消息處理步驟如下所示:

  1. 處理Native層的Message
  2. 處理Native層的Request
  3. 處理Java層的Message

題外話

Android消息機(jī)制中册踩,可以看到使用ThreadLocal存儲Looper對象泳姐,這里我想講解下線程局部存儲(TLS)

線程局部存儲(TLS)

線程局部存儲(TLS)是一種存儲持續(xù)期(Storage Duration)暂吉,對象的存儲在線程開始時分配胖秒,線程結(jié)束時回收每個線程都有該對象自己的實(shí)例慕的。

C中阎肝,使用關(guān)鍵字_Thread_local來定義線程局部變量,在頭文件<thread.h>定義thread_local為該關(guān)鍵字同義肮街,代碼如下所示:

#include <threads.h>
thread_local int foo = 0;

C++中风题,使用關(guān)鍵字thread_local來定義線程局部變量

Java中,使用ThreadLocal類來提供線程局部變量沛硅,普通變量可以被任何一個線程讀或者寫眼刃,而ThreadLocal創(chuàng)建的變量只能被當(dāng)前線程讀或者寫其他線程無法讀或者寫該變量摇肌;ThreadLocal類內(nèi)部類ThreadLocalMap采用開放地址法解決哈希沖突擂红,如果想深入了解,可以看下Java集合框架——Android中的HashMap源碼分析這篇文章的題外話围小。

我的GitHub:TanJiaJunBeyond

Android通用框架:Android通用框架

我的掘金:譚嘉俊

我的簡書:譚嘉俊

我的CSDN:譚嘉俊

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末昵骤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子肯适,更是在濱河造成了極大的恐慌变秦,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件框舔,死亡現(xiàn)場離奇詭異诉位,居然都是意外死亡浆兰,警方通過查閱死者的電腦和手機(jī)趴乡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門钠龙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人额港,你說我怎么就攤上這事饺窿。” “怎么了移斩?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵肚医,是天一觀的道長。 經(jīng)常有香客問我向瓷,道長肠套,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任猖任,我火速辦了婚禮你稚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘朱躺。我一直安慰自己刁赖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布长搀。 她就那樣靜靜地躺著宇弛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪源请。 梳的紋絲不亂的頭發(fā)上枪芒,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天彻况,我揣著相機(jī)與錄音,去河邊找鬼舅踪。 笑死纽甘,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的硫朦。 我是一名探鬼主播贷腕,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼咬展!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瞒斩,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤破婆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后胸囱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祷舀,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年烹笔,在試婚紗的時候發(fā)現(xiàn)自己被綠了裳扯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡谤职,死狀恐怖饰豺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情允蜈,我是刑警寧澤冤吨,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站饶套,受9級特大地震影響漩蟆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜妓蛮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一怠李、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蛤克,春花似錦捺癞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至儿倒,卻和暖如春版保,著一層夾襖步出監(jiān)牢的瞬間呜笑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工彻犁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叫胁,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓汞幢,卻偏偏與公主長得像驼鹅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子森篷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評論 2 354