国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > php开源 > 综合技术 > Android消息机制

Android消息机制

来源:程序员人生   发布时间:2016-11-29 09:00:38 阅读次数:2295次

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

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

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

MessageQueue
MessageQueue类提供1个消息队列,和插入、删除和提取消息的函数接口。
mPtr : 通过这个变量保存1个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:是不是正在等待被激活以获得消息。
1个线程最多只可以具有1个MessageQueue,安卓中通过ThreadLocal来保证1个线程中最多有1个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()之前1定要先履行这个方法。知道调用了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保证了1个线程里面只有1个Looper对象。关于ThreadLocal的原理大家可以到网上找点资料看1下,有点类似根据id寻觅值。

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

loop()
这个类中最重要的1个方法。让Looper开始工作从消息队列里取消息,处理消息Looper对象通过MessageQueue来寄存消息和事件。1个线程只能有1个Looper,对应1个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 : 线程的消息处理循环,其实不是每个线程都有消息处理循环。1般开发中用得比较多的是1个有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()
从消息池返回1个新的消息对象。实际上就是调用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()来处理。

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

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

public void handleMessage(Message msg) { }

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

MessageQueue中的Message包括3种类型:普通的同步消息,Sync barrier(target = null),异步消息(isAsynchronous() = true)。
MessageQueue的核心函数为enqueueMessage和next,前者用于向容器内添加Message,而Looper通过后者从MessageQueue中获得消息,并实现无消息情况下的等待。
MessageQueue把Android消息机制的Java实现和C++实现联系起来。
 每一个线程最多可以有1个Looper。
每一个Looper有且唯一1个MessageQueue
每一个Handler关联1个MessageQueue,由该MessageQueue关联的Looper履行(调用Hanlder.dispatchMessage)
每一个MessageQueue可以关联任意多个Handler
Looper API的调用顺序:Looper.prepare >> Looper.loop >> Looper.quit
Looper的核心函数是Looper.loop,1般loop不会返回,直到线程退出,所以需要线程完成某个work时,请发送消息给Message(或说Handler)**
生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------
分享到:
------分隔线----------------------------
关闭
程序员人生