Android技术21:Android异步消息处理线程
Android异步消息处理线程,该线程一直处于无限循环之中,每次从Message Queue中读取消息,然后回调消息处理的方法,Handler的HandlerMessage中处理消息。如果消息队列为空,该线程就挂,等待消息队列中有消息进来,就唤醒线程。
1.Android异步线程内部结构
在线程内部有一个或者多个Handler对象,外部程序通过Handler对象向线程发送异步消息,消息经过Handler传递到Message Queue对象中,每个线程内部只包含一个一个消息队列对象,线程主执行函数从消息队列中读取消息,并回调Handler对象方法handlerMessage()。
2.Thread Local Storage
程序员通过Looper类的静态方法prepare()为线程创建消息队列对象。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
1 private static void prepare(boolean quitAllowed) { 2 if (sThreadLocal.get() != null) { 3 throw new RuntimeException("Only one Looper may be created per thread"); 4 } 5 sThreadLocal.set(new Looper(quitAllowed)); 6 }
线程局部对象TLS,该对象是通过sThreadLocal的set方法设置进去。
3.Looper
Looper对象作用:一是创建消息队列,二是让当前线程提供静态方法loop()进入循环,并从消息队列中读取消息。
1 private Looper(boolean quitAllowed) { 2 mQueue = new MessageQueue(quitAllowed); 3 mRun = true; 4 mThread = Thread.currentThread(); 5 }
当需要把一个线程变为异步消息处理线程时,应该在Thread类的run()函数中先调用Looper.prepare()为线程创建一个消息队列对象Message Queue.然后调用Looper.loop()使当前线程进入消息处理循环。
1 public static void loop() { 2 final Looper me = myLooper(); 3 if (me == null) { 4 throw new RuntimeException("No Looper; Looper.prepare() wasn‘t called on this thread."); 5 } 6 final MessageQueue queue = me.mQueue; 7 8 // Make sure the identity of this thread is that of the local process, 9 // and keep track of what that identity token actually is. 10 Binder.clearCallingIdentity(); 11 final long ident = Binder.clearCallingIdentity(); 12 13 for (;;) { 14 Message msg = queue.next(); // might block 15 if (msg == null) { 16 // No message indicates that the message queue is quitting. 17 return; 18 } 19 20 // This must be in a local variable, in case a UI event sets the logger 21 Printer logging = me.mLogging; 22 if (logging != null) { 23 logging.println(">>>>> Dispatching to " + msg.target + " " + 24 msg.callback + ": " + msg.what); 25 } 26 27 msg.target.dispatchMessage(msg); 28 29 if (logging != null) { 30 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); 31 } 32 33 // Make sure that during the course of dispatching the 34 // identity of the thread wasn‘t corrupted. 35 final long newIdent = Binder.clearCallingIdentity(); 36 if (ident != newIdent) { 37 Log.wtf(TAG, "Thread identity changed from 0x" 38 + Long.toHexString(ident) + " to 0x" 39 + Long.toHexString(newIdent) + " while dispatching to " 40 + msg.target.getClass().getName() + " " 41 + msg.callback + " what=" + msg.what); 42 } 43 44 msg.recycle(); 45 }
4.Message Queue
从上面看出通过queue.next(),读取一条消息,但是在Framework中并没有消息队列对象,Message Queue两个主要函数读取消息和添加消息,分别为next(),enquenceMessage().但是真正实现并不是在Framework层而是通过JNI在C代码中实现。
1 private native static int nativeInit(); 2 private native static void nativeDestroy(int ptr); 3 private native static void nativePollOnce(int ptr, int timeoutMillis); 4 private native static void nativeWake(int ptr);
5.Handler
在构造Handler对象前,必须经过执行过Looper.prepare(),在Looper.loop()函数中,不同的Message对应不同的Handler对象,从而回调不同的handlerMessage()函数。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。