深入理解 Handler 消息机制

记得很多年前的一次面试中,面试官问了这么一个问题,你在项目中一般如何实现线程切换? 他的本意应该是考察 RxJava 的使用,只是我的答案是 Handler,他也就没有再追问下去了。在早期 Android 开发的荒芜时代,Handler 的确承担了项目中大部分的线程切换工作,通常包括子线程更新 UI 和消息传递。不光在我们自己的应用中,在整个 Android 体系中,Handler 消息机制也是极其重要的,不亚于 Binder 的地位。 ActivityThread.java 中的内部类 H 就是一个 Handler,它内部定义了几十种消息类型来处理一些系统事件。

Handler 的重要性毋庸置疑,今天就通过 AOSP 源码来深入学习 Handler。相关类的源码包含注释均已上传到我的 Github 仓库 android_9.0.0_r45 :

Handler.java

Looper.java

Message.java

MessageQueue.java

Handler

Handler 用来发送和处理线程对应的消息队列 MessageQueue 中存储的 Message。每个 Handler 实例对应一个线程以及该线程的消息队列。当你创建一个新的 Handler,它会绑定创建它的线程和消息队列,然后它会向消息队列发送 Message 或者 Runnable,并且在它们离开消息队列时执行。

Handler 有两个主要用途:

  1. 规划 Message 或者 Runnable 在未来的某个时间点执行
  2. 在另一个线程上执行代码

以上翻译自官方注释。说白了,Handler 只是安卓提供给开发者用来发送和处理事件的,而消息如何存储,消息如何循环取出,这些逻辑则交给 MessageQueueLooper 来处理,使用者并不需要关心。但要真正了解 Handler 消息机制,认真读一遍源码就必不可少了。

构造函数

Handler 的构造函数大致上可以分为两类,先来看第一类:

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

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

public Handler(Callback callback, boolean async) {
    // 如果是匿名类、内部类、本地类,且没有使用 static 修饰符,提示可能导致内存泄漏
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }

    // 从当前线程的 ThreadLocal获取 Looper
    mLooper = Looper.myLooper();
    if (mLooper == null) {  // 创建 Handler 之前一定要先创建 Looper。主线程已经自动为我们创建。
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue; // Looper 持有一个 MessageQueue
    mCallback = callback; // handleMessage 回调
    mAsynchronous = async; // 是否异步处理
}

这一类构造函数最终调用的都是两个参数的方法,参数中不传递 Looper,所以要显式检查是否已经创建 Looper。创建 Handler 之前一定要先创建 Looper,否则会直接抛出异常。在主线程中 Looper 已经自动创建好,无需我们手动创建,在 ActivityThread.javamain() 方法中可以看到。Looper 持有一个消息队列 MessageQueue,并赋值给 Handler 中的 mQueue 变量。Callback 是一个接口,定义如下:

public interface Callback {
    public boolean handleMessage(Message msg);
}

通过构造器参数传入 CallBack 也是 Handler 处理消息的一种实现方式。

再回头看一下在上面的构造函数中是如何获取当前线程的 Looper 的?

 mLooper = Looper.myLooper(); // 获取当前线程的 Looper

这里先记着,回头看到 Looper 源码时再详细解析。

看过 Handler 的第一类构造函数,第二类其实就很简单了,只是多了 Looper 参数而已:

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

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

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

直接赋值即可。

除此之外还有几个标记为 @hide 的构造函数就不作说明了。

发送消息

发送消息大家最熟悉的方法就是 sendMessage(Message msg) 了,可能有人不知道其实还有 post(Runnable r) 方法。虽然方法名称不一样,但最后调用的都是同一个方法。

sendMessage(Message msg)
sendEmptyMessage(int what)
sendEmptyMessageDelayed(int what, long delayMillis)
sendEmptyMessageAtTime(int what, long uptimeMillis)
sendMessageAtTime(Message msg, long uptimeMillis)

几乎所有的 sendXXX() 最后调用的都是 sendMessageAtTime() 方法。

post(Runnable r)
postAtTime(Runnable r, long uptimeMillis)
postAtTime(Runnable r, Object token, long uptimeMillis)
postDelayed(Runnable r, long delayMillis)
postDelayed(Runnable r, Object token, long delayMillis)

所有的 postXXX() 方法都是调用 getPostMessage() 将 参数中的 Runnable 包装成 Message,再调用对应的 sendXXX() 方法。看一下 getPostMessage() 的代码:

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

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

主要是把参数中的 Runnable 赋给 Message 的 callback 属性。

殊途同归,发送消息的重任最后都落在了 sendMessageAtTime() 身上。

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis); // 调用 Messagequeue 的 enqueueMessage() 方法
}

Handler 就是一个撒手掌柜,发送消息的任务转手又交给了 MessageQueue 来处理。

再额外提一点,enqueueMessage() 方法中的参数 uptimeMillis 并不是我们传统意义上的时间戳,而是调用 SystemClock.updateMillis() 获取的,它表示自开机以来的毫秒数。

MessageQueue

enqueueMessage()

Message 的入队工作实际上是由 MessageQueue 通过 enqueueMessage() 函数来完成的。

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) { // msg 必须有 target
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) { // msg 不能正在被使用
        throw new IllegalStateException(msg + " This message is already in use.");
    }

    synchronized (this) {
        if (mQuitting) { // 正在退出,回收消息并直接返回
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            // 插入消息队列头部,需要唤醒队列
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) { // 按消息的触发时间顺序插入队列
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

从源码中可以看出来,MessageQueue 是用链表结构来存储消息的,消息是按触发时间的顺序来插入的。

enqueueMessage() 方法是用来存消息的,既然存了,肯定就得取,这靠的是 next() 方法。

next()

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

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        // 阻塞方法,主要是通过 native 层的 epoll 监听文件描述符的写入事件来实现的。
        // 如果 nextPollTimeoutMillis = -1,一直阻塞不会超时。
        // 如果 nextPollTimeoutMillis = 0,不会阻塞,立即返回。
        // 如果 nextPollTimeoutMillis > 0,最长阻塞nextPollTimeoutMillis毫秒(超时),如果期间有程序唤醒会立即返回。
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                // msg.target == null表示此消息为消息屏障(通过postSyncBarrier方法发送来的)
                // 如果发现了一个消息屏障,会循环找出第一个异步消息(如果有异步消息的话),
                // 所有同步消息都将忽略(平常发送的一般都是同步消息)
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // 消息触发时间未到,设置下一次轮询的超时时间
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    // 得到 Message
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse(); // 标记 FLAG_IN_USE
                    return msg;
                }
            } else {
                // No more messages.
                // 没有消息,会一直阻塞,直到被唤醒
                nextPollTimeoutMillis = -1;
            }

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

            // If first time idle, then get the number of idlers to run.
            // Idle handles only run if the queue is empty or if the first message
            // in the queue (possibly a barrier) is due to be handled in the future.
            // Idle handle 仅当队列为空或者队列中的第一个消息将要执行时才会运行
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                // 没有 idle handler 需要运行,继续循环
                mBlocked = true;
                continue;
            }

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

        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        // 只有第一次循环时才会执行下面的代码块
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

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

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

        // Reset the idle handler count to 0 so we do not run them again.
        // 将 pendingIdleHandlerCount 置零保证不再运行
        pendingIdleHandlerCount = 0;

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

next() 方法是一个死循环,但是当没有消息的时候会阻塞,避免过度消耗 CPU。nextPollTimeoutMillis 大于 0 时表示等待下一条消息需要阻塞的时间。等于 -1 时表示没有消息了,一直阻塞到被唤醒。

这里的阻塞主要靠 native 函数 nativePollOnce() 来完成。其具体原理我并不了解,想深入学习的同学可以参考 Gityuan 的相关文 Android消息机制2-Handler(Native层)

MessageQueue 提供了消息入队和出队的方法,但它自己并不是自动取消息。那么,谁来把消息取出来并执行呢?这就要靠 Looper 了。

Looper

创建 Handler 之前必须先创建 Looper,而主线程已经为我们自动创建了 Looper,无需再手动创建,见 ActivityThread.javamain() 方法:

public static void main(String[] args) {
...
 Looper.prepareMainLooper(); // 创建主线程 Looper
...
}

prepareMainLooper()

public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

sMainLooper 只能被初始化一次,也就是说 prepareMainLooper() 只能调用一次,否则将直接抛出异常。

prepare()

public static void prepare() {
        prepare(true);
}

private static void prepare(boolean quitAllowed) {
    // 每个线程只能执行一次 prepare(),否则会直接抛出异常
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    // 将 Looper 存入 ThreadLocal
    sThreadLocal.set(new Looper(quitAllowed));
}

主线程中调用的是 prepare(false),说明主线程 Looper 是不允许退出的。因为主线程需要源源不断的处理各种事件,一旦退出,系统也就瘫痪了。而我们在子线程调用 prepare() 来初始化 Looper时,默认调动的是 prepare(true),子线程 Looper 是允许退出的。

每个线程的 Looper 是通过 ThreadLocal 来存储的,保证其线程私有。

再回到文章开头介绍的 Handler 的构造函数中 mLooper 变量的初始化:

mLooper = Looper.myLooper();
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

也是通过当前线程的 ThreadLocal 来获取的。

构造函数

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed); // 创建 MessageQueue
    mThread = Thread.currentThread(); // 当前线程
}

再对照 Handler 的构造函数:

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

其中的关系就很清晰了。

  • Looper 持有 MessageQueue 对象的引用
  • Handler 持有 Looper 对象的引用以及 Looper 对象的 MessageQueue 的引用

loop()

看到这里,消息队列还没有真正的运转起来。我们先来看一个子线程使用 Handler 的标准写法:

class LooperThread extends Thread {
    public Handler mHandler;

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

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

        Looper.loop();
    }
}

让消息队列转起来的核心就是 Looper.loop()

public static void loop() {
    final Looper me = myLooper(); // 从 ThreadLocal 中获取当前线程的 Looper
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue; // 获取当前线程的消息队列

   ...  // 省略部分代码

    for (;;) { // 循环取出消息,没有消息的时候可能会阻塞
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        ...  // 省略部分代码

        try {
            msg.target.dispatchMessage(msg); // 通过 Handler 分发 Message
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }

        ...  // 省略部分代码

        msg.recycleUnchecked(); // 将消息放入消息池,以便重复利用
    }
}

简单说就是一个死循环不停的从 MessageQueue 中取消息,取到消息就通过 Handler 来进行分发,分发之后回收消息进入消息池,以便重复利用。

从消息队列中取消息调用的是 MessageQueue.next() 方法,之前已经分析过。在没有消息的时候可能会阻塞,避免死循环消耗 CPU。

取出消息之后进行分发调用的是 msg.target.dispatchMessage(msg)msg.target 是 Handler 对象,最后再来看看 Handler 是如何分发消息的。

public void dispatchMessage(Message msg) {
    if (msg.callback != null) { // callback 是 Runnable 类型,通过 post 方法发送
        handleCallback(msg);
    } else {
        if (mCallback != null) { // Handler 的 mCallback参数 不为空时,进入此分支
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg); // Handler 子类实现的  handleMessage 逻辑
    }
}

private static void handleCallback(Message message) {
    message.callback.run();
}
  • Message 的 callback 属性不为空时,说明消息是通过 postXXX() 发送的,直接执行 Runnable 即可。
  • Handler 的 mCallback 属性不为空,说明构造函数中传入了 Callback 实现,调用 mCallback.handleMessage(msg) 来处理消息
  • 以上条件均不满足,只可能是 Handler 子类重写了 handleMessage() 方法。这好像也是我们最常用的一种形式。

Message

之所以把 Message 放在最后说,因为我觉得对整个消息机制有了一个完整的深入认识之后,再来了解 Message 会更加深刻。首先来看一下它有哪些重要属性:

int what :消息标识
int arg1 : 可携带的 int 值
int arg2 : 可携带的 int 值
Object obj : 可携带内容
long when : 超时时间
Handler target : 处理消息的 Handler
Runnable callback : 通过 post() 发送的消息会有此参数

Message 有 public 修饰的构造函数,但是一般不建议直接通过构造函数来构建 Message,而是通过 Message.obtain() 来获取消息。

obtain()

public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

sPool 是消息缓存池,链表结构,其最大容量 MAX_POOL_SIZE 为 50。obtain() 方法会直接从消息池中取消息,循环利用,节约资源。当消息池为空时,再去新建消息。

recycleUnchecked()

还记得 Looper.loop() 方法中最后会调用 msg.recycleUnchecked() 方法吗?这个方法会回收已经分发处理的消息,并放入缓存池中。

void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;

    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

总结

说到这里,Handler 消息机制就全部分析完了,相信大家也对整个机制了然于心了。

  • Handler 被用来发送消息,但并不是真正的自己去发送。它持有 MessageQueue 对象的引用,通过 MessageQueue 来将消息入队。
  • Handler 也持有 Looper 对象的引用,通过 Looper.loop() 方法让消息队列循环起来。
  • Looper 持有 MessageQueue 对象应用,在 loop() 方法中会调用 MessageQueue 的 next() 方法来不停的取消息。
  • loop() 方法中取出来的消息最后还是会调用 Handler 的 dispatchMessage() 方法来进行分发和处理。

最后,关于 Handler 一直有一个很有意思的面试题:

Looper.loop() 是死循环为什么不会卡死主线程 ?

看起来问的好像有点道理,实则不然。你仔细思考一下,loop() 方法的死循环和卡死主线程有任何直接关联吗?其实并没有。

回想一下我们经常在测试代码时候写的 main() 函数:

public static void main(){
    System.out.println("Hello World");
}

姑且就把这里当做主线程,它里面没有死循环,执行完就直接结束了,没有任何卡顿。但是问题是它就直接结束了啊。在一个 Android 应用的主线程上,你希望它直接就结束了吗?那肯定是不行的。所以这个死循环是必要的,保证程序可以一直运行下去。Android 是基于事件体系的,包括最基本的 Activity 的生命周期都是由事件触发的。主线程 Handler 必须保持永远可以相应消息和事件,程序才能正常运行。

另一方面,这并不是一个时时刻刻都在循环的死循环,当没有消息的时候,loop() 方法阻塞,并不会消耗大量 CPU 资源。

关于 Handler 就说到这里了。还记得文章说过线程的 Looper 对象是保存在 ThreadLocal 中的吗?下一篇文章就来说说 ThreadLocal 是如何保存 线程局部变量 的。

文章首发微信公众号: 秉心说 , 专注 Java 、 Android 原创知识分享,LeetCode 题解。

更多最新原创文章,扫码关注我吧!

原文地址:https://www.cnblogs.com/bingxinshuo/p/11470573.html

时间: 2024-10-12 22:29:31

深入理解 Handler 消息机制的相关文章

深入解析Android中Handler消息机制

Android提供了Handler 和 Looper 来满足线程间的通信.Handler先进先出原则.Looper类用来管理特定线程内对象之间的消息交换(MessageExchange).Handler消息机制可以说是Android系统中最重要部分之一,所以,本篇博客我们就来深入解析Android中Handler消息机制. Handler的简单使用 为什么系统不允许子线程更新UI 因为的UI控件不是线程安全的. 如果在多线程中并发访问可能会导致UI控件处于不可预期的状态,那为什么不对UI控件的访

Android Handler消息机制深入浅出

作为Android开发人员,Handler这个类应该是再熟悉不过了,因为几乎任何App的开发,都会使用到Handler这个类,有些同学可能就要说了,我完全可以使用AsyncTask代替它,这个确实是可以的,但是其实AsyncTask也是通过Handler实现的,具体的大家可以去看看源码就行了,Handler的主要功能就是实现子线程和主线程的通信,例如在子线程中执行一些耗时操作,操作完成之后通知主线程跟新UI(因为Android是不允许在子线程中跟新UI的). 下面就使用一个简单的例子开始这篇文章

Android Handler消息机制

在上一篇文章<Android AsyncTask异步任务>中我们介绍了如何使用AsyncTask异步处理网络通信和UI更新.在本文中将使用Handler消息机制来异步处理网络通信和UI更新. Google参考了Windows的消息机制,在Android系统中实现了一套类似的消息机制.学习Android的消息机制,有几个概念(类)必须了解: 1.Message 消息,理解为线程间通讯的数据单元.例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程. 2.M

[转]Handler消息机制详解

能简单说得我们尽量不复杂: 为了避免ANR,我们会通常把 耗时操作放在子线程里面去执行,因为子线程不能更新UI,所以当子线程需要更新的UI的时候就需要借助到安卓的消息机制,也就是Handler机制了. 注意:在安卓的世界里面,当 子线程 在执行耗时操作的时候,不是说你的主线程就阻塞在那里等待子线程的完成--也不是调用 Thread.wait()或是Thread.sleep().安卓采取的方法是,主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程.以这种方式设计你的应用程序,将能

【Android自助餐】Handler消息机制完全解析(二)MessageQueue的队列管理

Android自助餐Handler消息机制完全解析(二)MessageQueue的队列管理 Android自助餐Handler消息机制完全解析二MessageQueue的队列管理 添加到消息队列enqueueMessage 从队列取出消息next 第一段 第三段 第二段 从队列移除消息removeMessages 第一个while 第二个while 关于这个队列先说明一点,该队列的实现既非Collection的子类,亦非Map的子类,而是Message本身.因为Message本身就是链表节点(见

【Android自助餐】Handler消息机制完全解析(一)Message中obtain()与recycle()的来龙去脉

[Android自助餐]Handler消息机制完全解析(一)Message中obtain()与recycle()的来龙去脉 Android自助餐Handler消息机制完全解析一Message中obtain与recycle的来龙去脉 提供obtain 回收recycle 提供obtain() 在obtain的所有重载方法中,第一行都是Message m = obtain();,即调用空参的方法. 先来看一下这个空参方法 public static Message obtain() { synchr

Handler消息机制 源码解读

基本概念 Handler消息机制的作用 大家知道子线程没有办法对UI界面上的内容进行操作,如果操作,将抛出异常:CalledFromWrongThreadException,为了让子线程能间接操作UI界面,Android中引入了Handler消息传递机制,通过Handler切换到主线程进行UI操作. Handler.Looper.MessageQueue.Message的关系是什么? Handler用于发送和处理消息.而发出的Message经过一系列的周转后,最终会传递回Handler中,最后更

Handler消息机制与Binder IPC机制完全解析

1.Handler消息机制 序列 文章 0 Android消息机制-Handler(framework篇) 1 Android消息机制-Handler(native篇) 2 Android消息机制-Handler(实战篇) 2.Binder IPC机制 序列 文章 0 Binder开篇 1 Binder Driver初探 2 Binder Driver再探 3 启动Service Manager 4 获取Service Manager 5 注册服务(addService) 6 获取服务(getS

Android Handler 消息机制的日常开发运用与代码测试

很多时候我们需要对每个组件或者所有的UI线程要去负责View的创建并且维护它,例如更新冒个TextView的显示,都必须在主 线程中去做,我们不能直接在UI线程中去创建子线程,要利用消息机制:handler 本篇博客将带大家走进我们熟悉的Handler,顺带写了一个例子来验证Handler的消息机制,Handler通过对子线程的处理,实 现对UI的更新等操作 private TextView time; private Handler handler = new Handler(){ publi