Android-Handler源码解析-Handler

Android-Handler源码解析-Handler

源码版本:

  • Handler:SDK-31

导航:

成员变量

// 是否发现(检查)潜在的泄漏
private static final boolean FIND_POTENTIAL_LEAKS = false;
// Log的Tag
private static final String TAG = "Handler";
// 主线程Handler
private static Handler MAIN_THREAD_HANDLER = null;

// 此Handler的Looper
@UnsupportedAppUsage 
final Looper mLooper;

// 此Handler的消息队列,来自Looper对象。
final MessageQueue mQueue;

// 此Handler分发消息时,优先处理消息的Callback。
@UnsupportedAppUsage
final Callback mCallback;

// 是否是异步Handler,即是否send或post的消息全部都是异步消息,默认为false。
final boolean mAsynchronous;

// 跨进程通信,消息发送者。
@UnsupportedAppUsage
IMessenger mMessenger;

说明:

  1. Handler为什么需要持有LooperMessageQueue,因为Handler发送消息等操作需要知道发送到哪个MessageQueue,而MessageQueue需要从Looper中获取,以便发出的消息能进行轮询分发
  2. Looper相关介绍,请看Android-Handler源码解析-Looper
  3. MessageQueue相关介绍,请看Android-Handler源码解析-MessageQueue

创建Handler

想要使用Handler,首先要创建Handler,所以我们接下来看下它是如何被创建的。

new Handler()

默认Looper

Handler()

@Deprecated
public Handler() {
    this(null, false);
}

Handler(Callback)

@Deprecated
public Handler(@Nullable Callback callback) {
    this(callback, false);
}   

Handler(Callback, boolean)

/** @hide */
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) {
            // 匿名类、成员类、局部类,并且不是静态的,警告提示(以下Handler类应该是静态的,否则可能会发生泄漏)。
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }

    // 获取当前线程的Looper
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        // 当前线程没有Looper,则抛出异常提示(不能在没有调用Looper.prepare()的线程中创建handler)。
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    // 获取Looper的消息队列
    mQueue = mLooper.mQueue;
    // 记录CallBack
    mCallback = callback;
    // 记录是否是异步的
    mAsynchronous = async;
}

以上构造方法,使用默认Looper当前线程Looper)。如果这个线程没有looper,则抛出异常

说明:

  1. Handler()Handler(Callback)两个构造方法已经被标记@Deprecated(过时),因为在Handler构造过程中隐式选择一个Looper可能会导致错误,其中操作会自动丢失(如果Handler不需要新任务并退出)、崩溃(如果handler有时是在一个没有激活Looper线程创建的),或者竞态条件,其中handler关联的线程与作者预期的不符。相反,可以使用java.util.concurrent.Executor,或者使用Looper.getMainLooper,{link android.view.View#getHandler}或类似工具显式指定Looper。如果为了兼容性需要隐藏thread local行为,则使用new Handler(Looper.myLooper())让读者更清楚。
  2. Handler(Callback, boolean)两个构造方法已经被标记为@hide(隐藏),只能系统内部使用。
  3. 使用默认Looper当前线程Looper),如果这个线程没有looper,则抛出异常
  4. 参数Callback,为此Handler分发消息时,优先处理消息的Callback,详细见后面-分发Message
  5. 参数async,为此Handler发送消息时,是否全部发送异步/同步(默认同步)消息,详细见后面-发送Message
  6. 异步消息表示不需要同步消息进行全局排序中断事件异步消息不受MessageQueue.postSyncBarrier(long)引入的同步屏障的影响。
  7. MessageQueue同步屏障相关介绍,请看Android-Handler源码解析-MessageQueue-同步屏障

指定Looper

Handler(Looper)

public Handler(@NonNull Looper looper) {
    this(looper, null, false);
}

Handler(Looper, Callback)

public Handler(@NonNull Looper looper, @Nullable Callback callback) {
    this(looper, callback, false);
}

Handler(Looper, Callback, boolean)

/** @hide */
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

以上构造方法,使用指定Looper不是默认Looper

说明:

  1. Handler(Looper)Handler(Looper, Callback)两个构造方法未被标记@Deprecated(过时),并使用指定Looper推荐使用。
  2. Handler(Looper, Callback, boolean)构造方法已经被标记为@hide(隐藏),只能系统内部使用。

Handler.createAsync()

Handler.createAsync(Looper)

@NonNull
public static Handler createAsync(@NonNull Looper looper) {
    if (looper == null) throw new NullPointerException("looper must not be null");
    return new Handler(looper, null, true);
}

Handler.createAsync(Looper, Callback)

@NonNull
public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
    if (looper == null) throw new NullPointerException("looper must not be null");
    if (callback == null) throw new NullPointerException("callback must not be null");
    return new Handler(looper, callback, true);
}

Handler.createAsync()方法,为静态方法,创建一个异步Handler,其发布Message不受同步障碍(如显示vsync)的影响。

说明:

  1. 发送到异步handler的消息可以保证彼此之间的顺序,但不一定要按照来自其他Handlers的消息进行排序。

小结

  1. 创建-同步Handler,分为未指定Looper指定Looper两种方式创建
  • 未指定Looper,则使用当前线程Looper不推荐使用。
  • 指定Looper推荐使用,构造方法为Handler(Looper)Handler(Looper, Callback)
  1. 创建-异步Handler,使用Handler.createAsync(Looper)Handler.createAsync(Looper, Callback)方法创建

创建Message

想要使用Message,可以通过Handler创建Message,所以我们接下来看下它是如何被创建的。

obtainMessage()

@NonNull
public final Message obtainMessage() {
    return Message.obtain(this);
}

@NonNull
public final Message obtainMessage(int what) {
    return Message.obtain(this, what);
}

@NonNull
public final Message obtainMessage(int what, @Nullable Object obj) {
    return Message.obtain(this, what, obj);
}

@NonNull
public final Message obtainMessage(int what, int arg1, int arg2) {
    return Message.obtain(this, what, arg1, arg2);
}

@NonNull
public final Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
    return Message.obtain(this, what, arg1, arg2, obj);
}

以上obtainMessage()方法 ,从全局消息池返回一个新的消息。内部使用Message.obtain()方法创建消息,并将其Messagetarget为当前Handler

说明:

  1. Message.obtain()相关介绍,请看Android-Handler源码解析-Message-创建Message

小结

  1. handler.obtainMessage()方法,使用Message.obtain()方法创建消息,并将其Messagetarget为当前Handler

发送Message

Message创建好后,便可以发送消息了,Handler除了可以通过sendMessage()方法发送消息,还可以通过post()方法执行指定Callback任务,所以我们接下来看下它们是如何被发送的。

send-Message

sendMessage()

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

sendEmptyMessage()

public final boolean sendEmptyMessage(int what) {
    return sendEmptyMessageDelayed(what, 0);
}

sendEmptyMessageDelayed()

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}

sendEmptyMessageAtTime()

public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageAtTime(msg, uptimeMillis);
}

sendMessageDelayed()

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

sendMessageAtTime()

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

sendMessageAtFrontOfQueue()

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

以上方法,为发送立即消息发送延迟消息发送指定时刻消息将消息排在消息队列的前面

说明:

  1. sendMessage()sendEmptyMessage()发送立即消息消息,sendMessageDelayed()sendEmptyMessageDelayed()发送延迟消息消息,sendMessageAtTime()发送指定时刻消息sendMessageAtFrontOfQueue()将消息排在消息队列的前面
  2. sendMessageAtFrontOfQueue(),为将消息排在消息队列的前面,以便在消息loop下一次迭代中处理。此方法仅用于非常特殊的情况——它很容易使消息队列挨饿导致排序问题产生其它意想不到的副作用
  3. 发送立即消息发送延迟消息指定时刻发送将消息排在消息队列的前面,他们最终调用的都是enqueueMessage()方法。

我们接下来看下enqueueMessage()方法。

enqueueMessage()

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
    // 指定Message的Handler为此Handler
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    // 如果此Handler是异步的,则发送的所有消息都是异步的。
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    // 使用MessageQueue将消息加入到消息队列中
    return queue.enqueueMessage(msg, uptimeMillis); 
}

enqueueMessage()方法,为将Message加入到MessageQueue中。

说明:

  1. 指定MessagetargetHandler,使MessageHandler关联,以便使用Handler处理Message
  2. 如果此Handler异步的,则发送的所有消息都是异步的。
  3. uptimeMillis参数为消息执行时刻立即执行的为SystemClock.uptimeMillis()延时执行的为SystemClock.uptimeMillis() + delayMillis指定时刻发送的为指定的将消息排在消息队列的前面的为0
  4. MessageQueue入队消息相关介绍,请看Android-Handler源码解析-MessageQueue-入队Message

post-Callback

post()

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

postAtTime()

public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
    return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}

public final boolean postAtTime(@NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
    return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}

postDelayed()

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

public final boolean postDelayed(@NonNull Runnable r, @Nullable Object token, long delayMillis) {
    return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}

postAtFrontOfQueue()

public final boolean postAtFrontOfQueue(@NonNull Runnable r) {
    return sendMessageAtFrontOfQueue(getPostMessage(r));
}

以上方法,为执行指定Callback任务,由Runnable实现。底层也是通过getPostMessage()方法将Runnable包装Message然后调用对应发送消息的方法进行发送发送消息详细看上面的-send-Message

接下来我们来看一下getPostMessage()方法的实现。

getPostMessage()

private static Message getPostMessage(Runnable r) {
    // 使用复用获取新的Message
    Message m = Message.obtain();
    // 将Runnable保存到Message的callback中
    m.callback = r;
    return m;
}

@UnsupportedAppUsage
private static Message getPostMessage(Runnable r, Object token) {
    Message m = Message.obtain();
    m.obj = token;
    m.callback = r;
    return m;
}

getPostMessage()方法,使用复用机制获取新的Message,并将Runnable保存到Messagecallback中。

小结

  1. 发送消息分为send-Messagepost-Callbackpost-Callback底层也是通过send-Message进行发送(将Runnable保存到Messagecallback中)。
  2. sendMessageAtFrontOfQueue()postAtFrontOfQueue(),方法为将消息排在消息队列的前面,会使原来有序的队列变为无序的,谨慎使用
  3. 通过handler发送的消息,最终都会将MessageHandler关联,以便使用Handler处理Message
  4. 如果此Handler异步的,则发送的所有消息都是异步的。

分发Message

Looper.loop()方法开启后,并且此LooperMessageQueuenext()方法返回一个Message后,会调用HandlerdispatchMessage()方法,代码如下。

Loop->loopOnce()

private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {
        Message msg = me.mQueue.next(); // might block
        ...
        // 调用Handler分发消息
        msg.target.dispatchMessage(msg);
        ...
    }

接下来我们来看一下HandlerdispatchMessage()方法。

dispatchMessage()

Handler->dispatchMessage()

public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        // 处理Callback
        handleCallback(msg);
    } else {
        // 处理Message
        if (mCallback != null) {
            // handler的Callback不为空,优先它处理。
            if (mCallback.handleMessage(msg)) {
                // 返回true,表示handler的Callback已经处理,不再需要handleMessage()方法处理。
                return;
            }
        }
        // 使用handleMessage方法处理
        handleMessage(msg);
    }
}

dispatchMessage()方法,为分发消息,分为处理Callback处理Message,而的处理Message优先handlerCallback处理,其次再handleMessage()方法处理

说明:

  1. dispatchMessage()方法为public并且不是final,所以可以被覆写,一般不覆写此方法。

接下来我们先来看一下处理CallbackhandleCallback()方法。

handleCallback()

private static void handleCallback(Message message) {
    // 调用callback.run()方法(即runnable.run()方法)执行
    message.callback.run();
}

handleCallback()方法,直接调用messagecallback(即Runnable)的run()方法执行

接下来我们再来看一下优先处理MessageHandler.Callback类,其次再来看一下其次处理handleMessage()方法。

Handler.Callback类

public interface Callback {
    /**
     * @return 如果不需要进一步处理,则为True。
     */
    boolean handleMessage(@NonNull Message msg);
}

如果handler.mCallback有设置值,则优先它来处理,并且handleMessage()方法返回true,则不再需要handleMessage()方法处理。

handleMessage()

public void handleMessage(@NonNull Message msg) {
}

handleMessage()方法,为处理消息,我们可以通过Messagewhat的值来区分,来实现自己的逻辑。

说明:

  1. handleMessage()方法为public并且不是final,所以可以被覆写,一般覆写此方法。

小结

  1. 分发Message,它是通过HandlerdispatchMessage()方法进行分发处理
  2. 分发Message,它分为处理Callback处理Message
    2.1.处理Callback,直接调用callback(即Runnable)的run()方法执行。
    2.2.处理Message优先handlerCallback处理,其次再handleMessage()方法处理。
  3. dispatchMessage()handleMessage()方法均可以被覆写,一般只覆写handleMessage()方法即可。

移除Messages、Callbacks

removeMessages()

public final void removeMessages(int what) {
    mQueue.removeMessages(this, what, null);
}

public final void removeMessages(int what, @Nullable Object object) {
    mQueue.removeMessages(this, what, object);
}

removeCallbacks()

public final void removeCallbacks(@NonNull Runnable r) {
    mQueue.removeMessages(this, r, null);
}

public final void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
    mQueue.removeMessages(this, r, token);
}

removeCallbacksAndMessages()

public final void removeCallbacksAndMessages(@Nullable Object token) {
    mQueue.removeCallbacksAndMessages(this, token);
}

以上方法,为移除指定whatMessage或指定runnableCallbacks,全部都是通过调用MessageQueueremoveXX方法进行移除

说明:

  1. MessageQueue移除消息相关介绍,请看Android-Handler源码解析-MessageQueue-移除Message

小结

  1. 移除MessagesCallbacksremoveMessages()removeCallbacks()removeCallbacksAndMessages()方法,分别为移除所有符合条件的Messages、Callbacks。

是否有Messages、Callbacks

hasMessages()

public final boolean hasMessages(int what) {
    return mQueue.hasMessages(this, what, null);
}

hasCallbacks()

public final boolean hasCallbacks(@NonNull Runnable r) {
    return mQueue.hasMessages(this, r, null);
}

hasMessagesOrCallbacks()

public final boolean hasMessagesOrCallbacks() {
    return mQueue.hasMessages(this);
}

以上方法,为判断是否有指定whatMessage或指定runnableCallbacks,全部都是通过调用MessageQueuehasMessages方法进行判断

说明:

  1. MessageQueue是否有消息相关介绍,请看Android-Handler源码解析-MessageQueue-是否有Message

小结

  1. 是否有MessagesCallbackshasMessages()hasCallbacks()hasMessagesOrCallbacks()方法,分别为判断是否有符合条件的Messages、Callbacks。

其它

getMessageName()

public String getMessageName(@NonNull Message message) {
    if (message.callback != null) {
        // 是Callback类型,返回此Callback(即Runnable)的类名。
        return message.callback.getClass().getName();
    }
    // 是Message类型,返回此Message的what的十六进制。
    return "0x" + Integer.toHexString(message.what);
}

获取表示指定Message名称字符串默认实现,是Callback类型返回此Callback(即Runnable)的类名,是Message类型返回此Messagewhat十六进制

getLooper()

@NonNull
public final Looper getLooper() {
    return mLooper;
}

获取HandlerLooper对象

dump()

public final void dump(@NonNull Printer pw, @NonNull String prefix) {
    pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
    if (mLooper == null) {
        pw.println(prefix + "looper uninitialized");
    } else {
        mLooper.dump(pw, prefix + "  ");
    }
}

转储looper的状态,以进行调试。如果Looper为空,直接打印,否则调用Looperdump()方法。

说明:

  1. Looper转储的相关介绍,请看Android-Handler源码解析-Looper-其它

总结

以上就是Handler源码的Handler源码部分,Handler其它源码部分看下面导航。之后会出其它Android源码系列,请及时关注。如果你有什么问题,大家评论区见!

导航:

最后推荐一下我的网站,开发者的技术博客: devbolg.cn ,目前包含android相关的技术,之后会面向全部开发者,欢迎大家来体验!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容