《Android消息机制分析》由会员分享,可在线阅读,更多相关《Android消息机制分析(14页珍藏版)》请在人人文库网上搜索。
1、Android 消息机制(基于源码解析 )1. 消息机制概述Android 中的消息机制主要指的是 Handler 的运行机制, Handler 的运行需要底层的 MessageQueue和Looper、Message的支撑,下文会逐一分析。2. 为什么需要消息机制Android 中的消息机制主要是为了满足线程间通信而设计的,最重要的应用场景应该在于更 新 UIAndroid 规定访问 UI 只能在主线程中进行,如果在子线程中访问 UI ,那么程序就会抛出异 常 系统为什么不允许在自线程中访问UI 呢?这是因为 Android 的 UI 控件不是线程安全的, 如果在多线程中并发访问可能会导致U。
2、I 控件处于不可预期的状态。那为什么不对 UI 控件的访问加上锁机制呢?缺点有两个:首先加上锁机制会让 UI 访问的逻辑变得复杂; 其次锁机制会降低访问 UI 的效率,因为锁机制会阻塞某些现成的执行 鉴于这两个缺点,最简单且最高效的方法就是采用单线程模型来处理UI 操作,对于开发者来说也不是很麻烦,只是需要通过 Handler 切换下 UI 的访问执行线程即可3. Android 中线程的分类带有消息队列, 用来执行循环型任务 (例如主线程 ActivityThread , Android.os.HandlerThread ) 有消息时就处理,没有消息时就睡眠没有消息队列,用来执行一次性任务(。
3、例如 java.lang.Thread ) 任务一旦执行完成便退出4. 带有消息队列的线程具体实现主要涉及 4 个方面Message (消息)MessageQueue (消息队列)Looper (消息循环)Handler (消息发送和处理)4.1 消息队列说到MessageQueue,我们来看下它是干什么的/* Low-level class holding the list of messages to be dispatched by a* link Looper. Messages are not added directly to a MessageQueue,* but rather。
4、 through link Handler objects associated with the Looper.*You can retrieve the MessageQueue for the current thread with* link Looper#myQueue() Looper.myQueue().*/它是一个低等级的持有 Messages 集合的类,被 Looper 分发。 Messages 并不是直接加到 MessageQueue 的 , 而 是 通 过 Handler 对 象 和 Looper 关 联 到 一 起 。 我 们 可 以 通 过 Looper.myQueu。
5、e() 方法来检索当前线程的MessageQueue。4.2 Message在整个消息处理机制中,message又叫task,圭寸装了任务携带的信息和处理该任务的handler。我们看下这个类的注释* Defines a message containing a description and arbitrary data object that can be* sent to a link Handler. This object contains two extra int fields and an* extra object field that allow you to not do。
6、 allocations in many cases.* While the constructor of Message is public, the best way to get* one of these is to call link #obtain Message.obtain() or one of the* link Handler#obtainMessage Handler.obtainMessage() methods, which will pull* them from a pool of recycled objects.*/这个类定义了一个包含描述和一个任意类型对象。
7、的对象,它可以被发送给Handler。从注释里我们还可以了解到以下几点:尽管Message有public的默认构造方法,但是你应该通过Message.obtain()来从消息池中获得空消息对象,以节省资源。如果你的message只需要携带简单的int信息,请优先使用 Message.arg1和Message.arg2来传递信息,这比用 Bundle 更省内存用message.what来标识信息,以便用不同方式处理 message4.3 Looper/* This class contains the code required to set up and manage an event loo。
8、p* based on MessageQueue. APIs that affect the state of the queue should be* defined on MessageQueue or Handler rather than on Looper itself. For example,* idle handlers and sync barriers are defined on the queue whereas preparing the* thread, looping, and quitting are defined on the looper.*/这个类是基于。
9、消息队列用来设置和管理事件循环的代码, 对队列的改变应该在MessageQueue或Handler上定义,而不是在 Looper本身定义,例如空间处理和同步障碍应 该在队列上定义,然而准备线程、循环和退出在 Looper 本身定义,4.4 Handler /* A Handler allows you to send and process link Message and Runnable* objects associated with a threadssageQlinukeMue. Each Handlers message* instance is associated with a。
10、 single thread and that thread * queue. When you create a new Handler, it is bound to the thread /* message queue of the thread that is creating it -from that point on.* it will deliver messages and runnables to that message queue and execute* them as they come out of the message queue.There are two。
11、 main uses for a Handler: (1) to schedule messages and* runnables to be executed as some point in the future; and (2) to enqueue* an action to be performed on a different thread than your own.*Scheduling messages is accomplished with the* link #post, link #postAtTime(Runnable, long),* link #postDela。
12、yed, link #sendEmptyMessage,* link #sendMessage, link #sendMessageAtTime, and* link #sendMessageDelayed methods. The post versions allow* you to enqueue Runnable objects to be called by the message queue when* they are received; the sendMessage versions allow you to enqueue* a link Message object co。
13、ntaining a bundle of data that will be* processed by the Handlers link #handleMessage method (requiring that* you implement a subclass of Handler).*When posting or sending to a Handler, you can either* allow the item to be processed as soon as the message queue is ready* to do so, or specify a delay。
14、 before it gets processed or absolute time for* it to be processed. The latter two allow you to implement timeouts,* ticks, and other timing-based behavior.*When a* process is created for your application, its main thread is dedicated to* running a message queue that takes care of managing the top-l。
15、evel* applicati on objects (activities, broadcast receivers, etc) and any win dows* they create. You can create your own threads, and com muni cate back with* the main application thread through a Handler. This is done by calling* the same post or sen dMessage methods as before, but from* your new t。
16、hread. The give n Runn able or Message will the n be scheduled* in the Handle r s message queue and processed when appropriate.*/这个有点长,简单概括下:每一个Handler实例关联了一个单一的 ghread和这个thread的messagequeue当Handler的实例被创建的时候它就被绑定到了创建它的thread。它用来调度message和runnables在未来某个时间点的执行,还可以排列其他线程里执行的操作。Handler主要用的来管理某个线程(也可能是进程。
17、)的消息队列。比如处理主线程的消息队列,包含消息的发送和接收过程。消息的发送可以通过Post的一系列方法和 Se nde的一系列方法来实现。而post的一系列方法最终是通过send的一系列方法来实现的。这样就可以将一些耗时任务放到其他线程之中,待任务完成之后就往主线程的消息队列中添加一个消息,这样Han dler的Callback,即handleMessage就会被调用。但是Handler并不是线程安全的,因此建议将Handler作为一个静态内部类。所以Handler只是处理消息,耗时任务放在其他线程。4.5四元素的交互过程*、OcjHitchtr具体工作过程消息队列的创建消息循环消息的发送最。
18、基本的两个API带一个Runnable参数,会被转换为一个Message参数带一个Message参数,用来描述消息的内容Han dler.se ndMessageHan dler.post消息的处理基于消息的异步任务接口android.os.HandlerThread适合用来处于不需要更新 UI 的后台任务android.os.AyncTask适合用来处于需要更新 UI 的后台任务4.5.1 Looper 与消息队列的创建首先确认当前线程是否具有 Looper (主线程默认具有 Looper )如果没有则创建 我们知道 Android 上一个应用的入口,应该是 ActivityThread 。。
19、和普通的 Java 类一样,入口 是一个 main 方法。创建主线程源码示例:public static void main(String args) /省略部分无关代码 /创建 Looper 和 MessageQueue 对象,用于处理主线程的消息Looper.prepareMainLooper();/创建 ActivityThread 对象ActivityThread thread = new ActivityThread();/建立 Binder 通道 (创建新线程 )thread.attach(false);if (sMainThreadHandler = null) sMainThr。
20、eadHandler = thread.getHandler();if (false) Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, ActivityThread);/ End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);/消息循环运行Looper.loop();throw new RuntimeException(Main thread loop unexpectedly exited);UI )的我们可以看。
21、到主方法首先通过 Looper.prepareMainLooper() 初始化了我们主线程( Looper 并且启动它。然后就可以处理子线程和其他组件发来的消息了如果不是主线程的两线程进行通信,可以通过以下方式来创建class LooperThread extends Thread public Handler mHandler;public void run() /将当前线程初始化为 Looper 线程Looper.prepare();/ . 其他处理,如实例化 handler mHandler = new Handler() public void handleMessage(Messag。
22、e msg) / process incoming messages here;/ 开始循环处理消息队列Looper.loop();Looper 源码如下:public final class Looper private static final String TAG = Looper;/ sThreadLocal.get() will return null unless youve called prepare().static final ThreadLocal sThreadLocal = new ThreadLocal(); private static Looper sMainL。
23、ooper; / guarded by Looper.class/Looper 内的消息队列final MessageQueue mQueue;/ 当前线程final Thread mThread;private Printer mLogging;private Looper(boolean quitAllowed) mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();/* Initialize the current thread as a looper.* This gives you a cha。
24、nce 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) /试图在有 Looper 的线程中再次创。
25、建 Looper 将抛出异常if (sThreadLocal.get() != null) throw new RuntimeException(Only one Looper may be created per thread); sThreadLocal.set(new Looper(quitAllowed);/* Initialize the current thread as a looper, marking it as an* applications main looper. The main looper for your application* is created by 。
26、the Android environment, so you should never need* to call this function yourself.See also: link #prepare()*/public static void prepareMainLooper() prepare(false);synchronized (Looper.class) if (sMainLooper != null) beenthrow new IllegalStateException(The main Looper has already prepared.); sMainLoo。
27、per = myLooper();/省略部分无关代码 从中我们可以看到以下几点:prepare。其核心就是将 looper对象定义为ThreadLocal一个 Thread 只能有一个 Looper 对象prepare。方法会调用Looper的构造方法,初始化一个消息队列,并且指定当前线程ThreadLocal并不是一个 Thread,而是Thread的局部变量。当使用 ThreadLocal 维护变量时, ThreadLocal 为每个使用该变量的线程提供独立的变量副 本。所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。从线程的角度看,目标变量就象是线程的本地变量,。
28、这也是类名中“Local”所要表达的意思。在调用 Looper.loop() 方法之前,确保已经调用了 prepare(boolean quitAllowed) 方法,并且我 们可以调用 quite 方法结束循环接下来再看看 Looper.loop()/* Run the message queue in this thread. Be sure to call* link #quit() to end the loop.*/public static void loop() /得到当前线程 Looperfinal Looper me = myLooper();if (me = null) t。
29、hrow new RuntimeException(No Looper; Looper.prepare() wasnt called on this thread.);/得到当前 looper 的 MessageQueuefinal 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.clearCallingIdentit。
30、y();final long ident = Binder.clearCallingIdentity();/开始循环for (;) Message msg = queue.next(); / might blockif (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.mLo。
31、gging;if (logging != null) logging.println( Dispatching to + msg.target + + msg.callback + : + msg.what);将真正的处理工作交给message的target,即卩handlermsg.target.dispatchMessage(msg);if (logging != null) logging.println( klass = getClass();if (klass.isAnonymousClass() | klass.isMemberClass() | klass.isLocalClas。
32、s() & (klass.getModwww.shanxiwang.netifiers() & 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(Cant create handler inside thread that has not cal。
33、led Looper.prepare(); mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async;public Handler(Looper looper, Callback callback, boolean async) mLooper = looper;mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async;/省略部分无关代码 先看构造方法,其实里边的重点是初始化了两个变量,把关联 looper 的 MessageQueue 。
34、作为 自己的 MessageQueue,因此它的消息将发送到关联looper的MessageQueue上。有了 handler 之后,我们就可以使用 Handler 提供的 post 和 send 系列方法向 MessageQueue 上发送消息了。其实 post发出的Runnable对象最后都被封装成message对象接下来我们看一下 handler 是如何发送消息的/* Causes the Runnable r to be added to the message queue.* The runnable will be run on the thread to which this h。
35、andler is* attached.* param r The Runnable that will be executed.* return Returns true if the Runnable was successfully placed in to the* message queue. Returns false on failure, usually because the*looper processing the message queue is exiting.*/public final boolean post(Runnable r)return sendMess。
36、ageDelayed(getPostMessage(r), 0);* Enqueue a message into the message queue after all pending messages* before (current time + delayMillis). You will receive it in* link #handleMessage, in the thread attached to this handler.* return Returns true if the message was successfully placed in to the*mess。
37、age queue. Returns false on failure, usually because the*looper processing the message queue is exiting. Note that a*result of true does not mean the message will be processed - if*the looper is quit before the delivery time of the message*occurs then the message will be dropped.*/public final boole。
38、an sendMessageDelayed(Message msg, long delayMillis) if (delayMillis uptimeMillis.* The time-base is link android.os.SystemClock#uptimeMillis.* Time spent in deep sleep will add an additional delay to execution.* You will receive it in link #handleMessage, in the thread attached* to this handler.* p。
39、aram uptimeMillis The absolute time at which the message should be*delivered, using the*link android.os.SystemClock#uptimeMillis time-base.* return Returns true if the message was successfully placed in to the* message queue. Returns false on failure, usually because the* looper processing the messa。
40、ge queue is exiting. Note that a* result of true does not mean the message will be processed - if* the looper is quit before the delivery time of the message* occurs then the message will be dropped.*/public boolean sendMessageAtTime(Message msg, long uptimeMillis) MessageQueue queue = mQueue;if (qu。
41、eue = 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;i。
42、f (mAsynchronous) msg.setAsynchronous(true);return queue.enqueueMessage(msg, uptimeMillis);这里我们只列出了一种调用关系,其他调用关系大同小异,我们来分析一下调用getPostMessage(r),把runnable对象添加到一个 Message对象中。 sendMessageDelayed(getPostMessage(r), 0) , 基 本 没 做 什 么 操 作 , 又 继 续 调 用 sendMessageAtTime(msg, SystemClock.uptimeMillis() + dela。
43、yMillis) 方法,在这个方法里拿到 创建这个 Handler 对象的线程持有的MessageQueue。调用 enqueueMessage(queue, msg, uptimeMillis) 方法,给 msg 对象的 target 变量赋值为当前的 Handler 对象,然后放入到 MessageQueue。那发送消息说完了,那我们的消息是怎样被处理的呢?我们看到 message.target为该handler对象,这确保了 looper执行到该 message时能找到处理 它的handler,即loop()方法中的关键代码。/* Callback interface you can u。
44、se when instantiating a Handler to avoid* having to implement your own subclass of Handler.* param msg A link android.os.Message Message object* return True if no further handling is desired*/public interface Callback public boolean handleMessage(Message msg); * Subclasses must implement this to rec。
45、eive messages. */public void handleMessage(Message msg) /* Handle system messages here.*/public void dispatchMessage(Message msg) if (msg.callback != null) handleCallback(msg); else if (mCallback != null) if (mCallback.handleMessage(msg) return; handleMessage(msg);private static void handleCallback(。
46、Message message) message.callback.run();我们看到这里最终又调用到了我们重写的han dleMessage(Message msg)方法来做处理子线程发来的消息或者调用handleCallback(Message message)去执行我们子线程中定义并传过来的操作为什么主线程不会因为 Looper.loop() 里的死循环卡死或者不能处理其他事务这里涉及到的东西比较多,概括的理解是这样的handler 机制是使用 pipe 来实现的,主线程没有消息处理时会阻塞在管道的读端。binder 线程会往主线程消息队列里添加消息, 然后往管道写端写一个字节, 这样就能唤醒主 线程从管道读端返回,也就是说queue .n ext()会调用返回。主线程大多数时候都是处于休眠状态,并不会消耗大量 CPU 资源。既然是死循环又如何去处理其他事务呢?答案是通过创建新线程的方式。我们看到 main 方法里调用了 thread.attach(false) ,这里便会创建一个 Binder 线程(具体是指 ApplicationThread , Binder 的服务端,用于接收系统服务 AMS 发送来的事件) ,该 Binder 线程通过 Handler 将 Message 发送给主线程。