Android 异步消息处理机制之Handler、Message、Looper

Android 异步消息处理机制的出现主要是为了解决android系统中不允许在子线程中不能更新UI,而只能必须在主线程(即UI线程)中进行更新的问题;

下面详细介绍下android异步消息处理机制中的三元素(Handler、Message、Looper);

我们首先来分析下Handler:

每个Handler实例都与单个线程(Thread)以及该线程的消息队列(MessageQueue)相关联;当您创建一个新的Handler实例时,该Handler实例将会绑定到创建该实例的线程(Thread)及该线程的消息队列(MessageQueue);官方的原话是: Each Handler
instance is associated with a single thread and that thread's message queue.  When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it.

上面的原因是:Handler实例的创建依赖于Looper实例;而一个线程(Thread)中最多只能创建一个Looper实例,因此Handler实例单个线程(Thread)以及该线程的消息队列(MessageQueue)相关联;部分源代码如下:

public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }


Handler实例可以通过调用sendMessage()系列方法以及post()系列方法来发送消息;通过调用removedCallbacks()系列方法来实现清除消息;


我们继续分析Message:

消息(Message)是线程之间进行通信的媒介;Message中有个很重要的成员target,它的数据类型是Handler,说到这里,恐怕大家已经猜到了这个target的作用了吧。没错,它的作用就是:将Message 实例与Handler实例进行绑定;从而实现Message与Handler的一一对应;

补充:官方建议消息的获取可以通过调用Message.obtain()方法来实现;


我们最后再来分析Looper:

之所以把Looper放到最后来分析,那是因为我认为它在异步消息处理机制中的分量属于最重的;

Looper类的作用,官方的原话是:Class used to run a message loop for a thread. 中文翻译就是:用于为线程运行消息循环的类。很准确,Looper类的作用就是为线程运行消息循环的类;

那异步消息处理机制中是Looper实例是如何被创建以及它是如何运行消息循环的呢?下面我们一一来分析;

Looper实例的创建是在Looper类的静态方法prepare()中被创建的;同时android 系统为了保证一个线程只能创建一个Looper实例,使用的jdk中标准的ThreadLocal类;通过调用ThreadLocal实例的set()、get()来实现;官方源代码为:

private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
}

那线程中消息循环是如何运行的呢?

消息循环是通过调用Looper类的静态方法loop()来实现的;loop方法中实现了一个死循环;部分源代码如下:

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

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

            msg.target.dispatchMessage(msg);

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

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

            msg.recycle();
        }

代码中有几点这里注意下;第一点就是消息的获取 Message msg = queue.next();这个是同步的,可能会出现阻塞;第二点就是Message实例的判空,这里实现非常巧妙,巧妙之处就是外界可以通过调用Looper的静态退出方法quit()来实现循环结束;原理其实就是销毁消息队列;

补充:Looper中有个非常重要的MessageQueue类型的 final 成员 mQueue;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值