android 进程/线程管理(四)续----消息机制的思考(自定义消息机制)
继续分析handler 和looper
先看看handler的
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
所以消息的处理分层三种,就是
1.传入一个runnable让handler处理。
2.传入要处理的hanglemessage
3.或者子类复写handlermessage。
其实本质是一样的,就是把怎么处理的这个方法,在dispatchMessage的时候分发。
如果我们有特殊的需求,完全可以重写dispatchMessage,分发给我们需要的方法。
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new Message(); }
obtainMessage()方法提供了一个消息池,以防止消息过多产生的内存问题。这个池是static的,也就是所有app共享的。
每次获取消息,poolsize就会减一。然后在looper.loop消息处理后,会调用
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 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(); } }
public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
释放这条已经使用过的消息。
线程池的概念也是如此。
下面我们看看looper:
Looper就是thread里面跑起消息机制的东西,顾名思义,“循环”。
如我写的demo,没有looper这个东东,也是可以实现消息循环的,那android为什么还要搞这么个类出来。
我想是基于如下的原因:
1.我在工作线程中,怎么发消息到主线程。
handler传入getMainLooper(),然后就可以发消息到主线程,进行UI更新等操作。
handler里面的looper绑定了queue。所以hander会给main messagequeue发送消息。
2.代码的提炼,既然循环的过程都是相同的,完全可以把这个过程提炼出来。
@Override public void run() { TraceLog.i("MyLoopThread looper prepare"); Looper.prepare(); myLooper = Looper.myLooper(); mHandler = new MyHandler(myLooper); Looper.loop(); }
只要如此简单的几句code,thread里面就已经搭建好了消息系统,实在是太神奇了!
再来看看looper.loop
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 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(); // might block
首先,这句之前有过分析,就是当消息队列没有消息的时候,会block住,直到有消息传过来。
msg.target.dispatchMessage(msg);
每条消息只有一个处理位置,就是发送他的handler
msg.recycle();
消息结束后释放,这样整个消息池就可以循环使用了。
可以说android的消息机制是参考的许多成熟的消息机制的基础上,创建而成的,有位难得的是,
他不仅仅是操作系统的使用,更是给我们android 应用开发者使用的一套工具。
学习android源码,对我们自己搭建消息机制有很大的借鉴作用。
参考:
1.《深入理解android内核设计思想》林学森
2.《Android内核剖析》
相关文章:
android 进程/线程管理(三)----Thread,Looper / HandlerThread / IntentService
posted on 2015-08-09 22:32 Joyfulmath 阅读(959) 评论(0) 编辑 收藏 举报