Android消息机制

最近决定把之前学习过的东西整理一遍,然后把写得一些代码review一遍,今天来学习一下消息机制,之前学过,没太搞清楚,有很多都忘记得差不多了,终究到底还是自己用得太少了,要多实践多实践。
1、首先上图(图片来源于别人的博客,盗图一枚)
这里写图片描述

从这张图我们可以看到涉及到消息机制的一些类,比如Looper、Message、MessageQueue、Handler等,以及里面的成员变量和方法。下面我们来学习一下这几个类。

Message:
what : what this message is about.用户自定义的消息码,以便接受者可以识别。每个Handler 对消息码有自己的命名空间,所以不用担心和其他的handler冲突。在消息处理中,我们可以根据这个字段的不同的值进行不同的处理。
arg1和arg2 :这两个参数是为了减小开销的替代物,就是你要是使用setData()存放少数几个整型数值的话。
obj : 发送给接收者的任意对象。当我们使用Messenger跨进程发送消息的时候,如果是Parcelable框架类的话必须是非空的。对于一般的数据一般使用setData()传递。
target : 处理消息的handler。
when :消息什么时候入队列,什么时候提交,什么时候回收这样的标志吧。
callback : handler发送消息的时候可以post一个runnable对象,会触发回调。
next:下一个消息,看代码我们知道消息是以链表一样的形式存储的,而消息对列是以对列的方式处理消息,先进入的消息先处理
obtain() : 推荐使用这样的方式获得消息对象,效率会更高
recycle() : 当消息处理完后,回收消息对象

MessageQueue
MessageQueue类提供一个消息队列,以及插入、删除和提取消息的函数接口。
mPtr : 通过这个变量保存一个Native层的NativeMessageQueue对象
mMessages : 保存接收到的Message消息。
mQuitAllowed: 是否允许终止,如果允许的话该值为true。

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

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }

mQuitting : 是否终止了。

private boolean isPollingLocked() {
        // If the loop is quitting then it must not be idling.
        // We can assume mPtr != 0 when mQuitting is false.
        return !mQuitting && nativeIsPolling(mPtr);
    }

mBlocked:是否正在等待被激活以获取消息。
一个线程最多只可以拥有一个MessageQueue,安卓中通过ThreadLocal来保证一个线程中最多有一个Looper

Looper
Threads by default do not have a message loop associated with them.线程默认情况下是没有消息循环的。实现Thread的消息循环和消息派发,缺省情况下Thread是没有这个消息循环的既没有Looper;
需要主动去创建,然后启动Looper的消息循环loop;与外部的交互通过Handler进行;Looper 的构造函数很简单,创建MessageQueue,保存当前线程到 mThread 中。但它是私有的,只能通过两个静态函数 prepare()/prepareMainLooper() 来调用。
mQueue : 消息对列
prepare() : 初始化当前线程作为Looper。在调用loop()之前一定要先执行这个方法。知道调用了quite这个方法。

This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.

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

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

void prepareMainLooper()
初始化当前线程为looper,并且使其作为程序的主looper。通常是由程序根据环境创建的,所以开发者不建议使用这个方法。

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

myLooper()
获得当前线程的looper,sThreadLocal是 ThreadLocal sThreadLocal 。ThreadLocal保证了一个线程里面只有一个Looper对象。关于ThreadLocal的原理大家可以到网上找点资料看一下,有点类似根据id寻找值。

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

loop()
这个类中最重要的一个方法。让Looper开始工作从消息队列里取消息,处理消息Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue

    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            if (traceTag != 0) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

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

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

            msg.recycleUnchecked();
        }
    }

void quit()
Quits the looper

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

Handler
mLooper : 线程的消息处理循环,并不是每一个线程都有消息处理循环。一般开发中用得比较多的是一个有Looper的Thread实现,HandlerThread。
mQueue : 消息对列对象,是成员对象mLooper的成员变量。


        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;

mCallback 提供了另一种使用Handler 的简便途径:只需实现回调接口 Callback,而无需子类化Handler。mAsynchronous 是标识是否异步处理消息

obtainMessage()
从消息池返回一个新的消息对象。实际上就是调用Message.obtain();

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

boolean sendMessage(Message msg)
将消息push到消息对列里面所有等待消息的最后面,在规定的时间内,线程里面的handler会受到这个消息。

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

boolean post(Runnable r)
将Runnable对象添加到消息对列里面,这个Runnable对象将被该线程的handler处理。如果成功添加到消息对列里面的话返回true。失败返回false,失败通常是looper处理的这个消息正在对列中退出。

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

void dispatchMessage(Message msg)
顾名思义这个方法是处理消息的。会根据不同的条件调用不同的函数。在传入的这个Message对象执行Message.obtain()的时候会对msg.callback进行赋值。

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

所以在查看消息处理对应的函数时,要看消息是否是通过obtain()获得的,如果是那么消息处理就会交由传递参数中callback.run()来处理。而mCallback 则是在实例化Handler的时候初始化赋值的。如果msg.callback == null,且 mCallback == null,则由Handler自身的handleMessage()来处理。

**在判断调用哪个消息处理函数时,一定要先看是否在调用obtain构造消息的时候是不是传递了msg或Runable参数,如果没有,则判断在构造Handler时是否将
Callback 函数当作参数传递了进来,最后再看自己的Handler是否重写了handleMessage函数。**

void handleMessage(Message msg)
子类必须实现这个方法,去接收消息,然后再进行一些处理。

public void handleMessage(Message msg) {
    }

**> MessageQueue作为一个容器,保存了所有待执行的消息。

MessageQueue中的Message包含三种类型:普通的同步消息,Sync barrier(target = null),异步消息(isAsynchronous() = true)。
MessageQueue的核心函数为enqueueMessage和next,前者用于向容器内添加Message,而Looper通过后者从MessageQueue中获取消息,并实现无消息情况下的等待。
MessageQueue把Android消息机制的Java实现和C++实现联系起来。
 每个线程最多可以有一个Looper。
每个Looper有且仅有一个MessageQueue
每个Handler关联一个MessageQueue,由该MessageQueue关联的Looper执行(调用Hanlder.dispatchMessage)
每个MessageQueue可以关联任意多个Handler
Looper API的调用顺序:Looper.prepare >> Looper.loop >> Looper.quit
Looper的核心函数是Looper.loop,一般loop不会返回,直到线程退出,所以需要线程完成某个work时,请发送消息给Message(或者说Handler)**
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值