Android更新Ui进阶精解(二)
来源:互联网 发布:新装办公室网络布线 编辑:程序博客网 时间:2024/05/17 02:02
《代码里的世界》
用文字札记描绘自己 android学习之路
转载请保留出处 by Qiao
http://blog.csdn.net/qiaoidea/article/details/45115047
【导航】
Android更新Ui的几种方法和见解 android更新ui基本常用方法
Android更新Ui进阶精解(一) android ui线程检查机制
Android更新Ui进阶精解(二) android 线程更新UI机制
1.回顾
第一篇讲了对Ui线程更新的方法和见解,然后接着讲了线程检查机制,这里来详细分析下更新Ui的核心——Android中消息系统模型。当然,这里要讲的其实也已经不再简简单单地是更新Ui的范畴了。不过还是很值得学习和分析一下。另外,其实网上关于这方面的讲解也有很多了,本篇也是综合整理并用自己的理解加以描述和概括。同时也感谢有更高造诣的大大能予以批评指正。
提炼
Android中的消息机制主要有如下几个要点,这里也着重围绕这些内容来讲解:
1. Handler 调度消息和runnable对象在不同线程中执行相应动作。
2. Looper消息泵,用来为一个线程开启一个消息循环
3. MessageQueue 遵循FIFO先进先出规则的消息队列,以链表形式存取Message,供looper提取
(为了深入了解,已从源码从提取这几个类
Handler/Looper/MessageQueue/Message .java 方便新手下载查看)
2.分析
为了方便分析,借用一下找到的模型图综合看一下:
首先在一个线程中初始化一个looper并prepare(准备),然后创建该looper对象的处理对象Handler,接着当需要交互变更时,可以在其他线程(或自身线程)中使用handler发消息至该消息队列MessageQueue,最后looper会自动有序抽取消息(没有消息则挂起),交给handler执行消息处理逻辑。
Orz,我的概念描述还是一塌糊涂,还是转代码说明吧:
比如我们有个线程专门负责一类处理逻辑,并且只允许该线程来处理这类逻辑,那么我们怎么做到呢?
1. 在一个线程里边定义一个Looper
Looper.prepare(); //稍微有点儿多,详细见下文
2.定义一个处理消息的Handler
handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); //处理逻辑 } };
3.启动looper,并开始工作,轮询消息
Looper.loop(); //详细见下文 //要停止的话,使用Looper.quit();
4.在其他线程将要处理的数据data或回调对象callback以消息Message模式通过Handler发至该消息队列MessageQueue
handler.sendMessage(msg)
5.Looper的loop()方法会从消息队列中取到该消息并唤醒处理逻辑
//即loop()方法中的代码 for (;;) { //显然这个死循环一直在等待消息到来并处理 Message msg = queue.next(); // 取一条消息 if (msg == null) { return; } msg.target.dispatchMessage(msg); //调用消息绑定的handler执行处理逻辑 //other code.... }
6.handler跳转到执行处理逻辑的过程
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(Message message) { message.callback.run(); }
以上便是整个消息系统的过程,后边我们会逐个分析精讲。
3.回到我们更新UI讲解
在ActivityManagerService为Android应用程序创建新的进程并启动activity时候,主线程ActivityThread首先被创建。该进程 Process.java@start(“android.app.ActivityThread”,…)会加载执行ActivityThread的静态成员函数main,打开该方法:
public static void main(String[] args) { //other code.. 我们只看有用的部分,其他暂略过 Looper.prepareMainLooper(); //准备looper,注,绑定的为当前主线程 ActivityThread thread = new ActivityThread();//开启一个新ActivityThread线程 thread.attach(false);//最后执行到activity //other code.. Looper.loop(); //启动looper
这个静态函数做了两件事情,一是在主线程中创建了一个ActivityThread实例,二是通过Looper类使主线程进入消息循环。
然后,代码经过一系列逻辑( ActivityThread.attach->IActivityManager. attachApplication -> attachApplicationApplicationThread.scheduleLaunchActivity ->… ->ActivityThread.performLaunchActivity ),最终会调用activity的attach方法。
我们打开activity类。可以看到,它定义了uiThread和Handler参数
ActivityThread mMainThread;//对应上边的ActivityThread线程 private Thread mUiThread;//主Ui线程 final Handler mHandler = new Handler();//这个handler就是activity用来处理Ui的了。我们自己定义的handler其实等于重新定义了这个mHandler;
我们来看activity的attach方法:
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, IVoiceInteractor voiceInteractor) { mUiThread = Thread.currentThread();//当前主线程Ui线程 mMainThread = aThread; //对应上边的ActivityThread线程 }
所以,当我们要更新UI的时候,都会用到sendMessage,比如使用runOnUiThread,来看下这个方法
public final void runOnUiThread(Runnable action) { /** *如果当前线程不为Ui主线程则使用定义好的mHandler */ if (Thread.currentThread() != mUiThread) { mHandler.post(action); } else { action.run(); }}
打开post方法:
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
还是熟悉的配方,还是熟悉的味道。。封装成消息,然后发送出去。好,我们再回头看看最初第一篇文章里的四种方法:
1.new 一个handler来 sendMessage();
2.利用new handler来post
不过是把上边已经定义好Activity的mHandler重新定义了一遍,然后封装成消息发送出去;
3.runOnUiThread
同样不过是用了Activity的mHandler发送消息;
4.view.post
稍微看一下代码:
public boolean post(Runnable action) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { return attachInfo.mHandler.post(action); } // Assume that post will succeed later ViewRootImpl.getRunQueue().post(action); return true; }
对于AttachInfo应该不算陌生吧,附加view到Activity的时候会把activity的一些属性附加给AttachInfo,这里同样调用取得mHandler然后再post。。绕了一圈又回来了。
综上看来,整个UI更新机制其实就是Android消息系统模型的一个简单实现。至此,我们的更新UI部分也算讲完了,那么作为补充部分,还是从源码上完整细致的过一下整个消息系统模型吧。
4.精解
这里通过剖析源码来理解各部分的具体实现,再结合前面讲的内容加以融会贯通,便于深入理解最终达到在不同场景的熟练使用。
我们将按照顺序来逐个查看。
首先说说消息对象,毕竟其他类操作的最基本元素也都是它。
4.1 Message
public final class Message implements Parcelable { //继承Parcelable 用于数据传递 /**几种数据类型**/ public int arg1; public int arg2; public Object obj; Bundle data; public int what;//供handler处理的消息识别标识身份 long when;//什么时候处理该消息 Handler target;//处理该消息的目标handler Runnable callback; //回调方法 int flags;//标签标识 static final int FLAG_IN_USE = 1 << 0;//是否可用(回收利用) static final int FLAG_ASYNCHRONOUS = 1 << 1; static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE; public Messenger replyTo;//可选对象,可以用来记录发送方或接收者 Message next;//这条消息的下一条消息 /** *开一个消息池,便于循环利用消息,避免生成新对象并分配内存 */ private static final Object sPoolSync = new Object(); private static Message sPool; private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50;}
既然提到消息池又在前面讲了利用obtain()节省内存资源,那么我们就看下这个obtain()
/** *从消息池中返回一个新的消息实例,避免我们通常情况下分配新对象。 */ public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new Message(); }
然后就是基于此方法的一系列运用:先调用obtain()方法,然后把获取的Message实例的 各种参数赋值传参。
//取一个消息对象,把已存在的消息内容赋值过去 public static Message obtain(Message orig) { Message m = obtain(); m.what = orig.what; m.arg1 = orig.arg1; m.arg2 = orig.arg2; m.obj = orig.obj; m.replyTo = orig.replyTo; if (orig.data != null) { m.data = new Bundle(orig.data); } m.target = orig.target; m.callback = orig.callback; return m; } public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj) { Message m = obtain(); m.target = h; m.what = what; m.arg1 = arg1; m.arg2 = arg2; m.obj = obj; return m; } //调用obtain并赋值,不再一一列出 public static Message obtain(Handler h) {//..} public static Message obtain(Handler h, Runnable callback) {//..} public static Message obtain(Handler h, int what) {//...} public static Message obtain(Handler h, int what, Object obj) {//...} public static Message obtain(Handler h, int what, int arg1, int arg2) {//...}
然后就是回收释放recycle,它返回一个消息池实例。释放之后将不能再使用此方法。
public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } } //清空所有数据 void clearForRecycle() { flags = 0; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; when = 0; target = null; callback = null; data = null; } //拷贝消息内容 public void copyFrom(Message o) { this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM; this.what = o.what; this.arg1 = o.arg1; this.arg2 = o.arg2; this.obj = o.obj; this.replyTo = o.replyTo; if (o.data != null) { this.data = (Bundle) o.data.clone(); } else { this.data = null; } }
后边就是get和set方法以及Parcelable 的读写。
4.2 Looper
先看他所定义的属性:
public class Looper { private static final String TAG = "Looper"; static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper;//唯一对应一个主线程的looper静态实例 final MessageQueue mQueue;//消息队列 final Thread mThread; //当前绑定线程 volatile boolean mRun; //是否允许退出 private Printer mLogging;//日志打印 //....各种方法体....}
通常操作系统都为线程提供了内部存储空间,一个线程对应一个内存空间,因此这里很方便的为一个线程定义唯一对应的looper实例:ThreadLocal< Looper > 这个有点类似C中申请内存大小 *malloc(sizeof Looper),或者我们可以简单理解为只作用于当前线程的new Looper.
而sMainLooper是当前应用程序的主线程looper,区别是适用于主线程。
我们再看他的构造方法:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); }
此构造方法是私有的,即不允许在外部实例化,这样通过单例模式保证外部从该线程取得looper唯一。另外它主要初始化了mQueue 、mRun 和 mThread 几个属性,并绑定了当前线程。找一下它调用实例化的部分:
//重载,主要看下边的prepare(boolean quitAllowed)方法 public static void prepare() { prepare(true); } /** *初始化当前线程作为Looper并存为本地变量, *并由此来创建handler和处理程序 * *@quitAllowed 是否允许退出(循环取消息) *通过调用loop()和quit()来开启和结束循环 */ private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { //保证一个线程唯一对应一个Looper throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed));//在线程中初始化一个实例 }
sThreadLocal的get和set,负责在内存中存取与线程唯一对应的looper。
同时我们会注意到有两个方法prepareMainLooper和getMainLooper:
/** *初始化当前线程作为Looper并作为android应用的取消息逻辑, *是由当前运行环境来创建,不需要手动调用 */ public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { //加锁,保证实例化唯一一个looper if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } /** * 返回当前应用程序主线程的looper实例 */ public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } }
这部分是共应用程序初始化的时候调用的,我们一般用不到,不过也可以看出只是初始化了主线程的looper。
好的,基本的初始化工作也已经完成了,来看该类中的核心部分,循环取消息的loop()
/** * 启动队列的循环取消息操作,直到调用quit()退出 */ 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; // 确保当前线程是本地进程的唯一标示 Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); //开始循环取消息操作 for (;;) { Message msg = queue.next(); //取下一条消息 if (msg == null) { // 如果消息队列没有消息则挂起 return; } // 打印日志部分 Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } //调用消息处理逻辑(回调和执行handler处理) msg.target.dispatchMessage(msg); if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // 确保在处理消息逻辑时当前线程并没有被打断 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(); } }
基本都有备注,不用过多解释了。msg.target.dispatchMessage前面已经讲过,后便可能会在拉出来遛遛。
其他再就是基本的get和打印和异常捕获相关的了,有兴趣的可以自己去看一下。
4.3 MessageQueue
类的描述简要翻译一下:
MessageQueue是一个低级类,负责维护一个需要被Looper派发处理的消息列表。其消息对象是通过hanlder绑定到looper上的,而不是直接添加到消息队列中去的。
其实即MessageQueue只是一个消息队列,提供给handler加入和Looper取出消息操作,这两个接口分别是 enqueueMessage(Message msg, long when) 和 next()。
先看属性:
public class MessageQueue { // 消息队列是否可以退出 private final boolean mQuitAllowed; Message mMessages;//message实例(类似链表) //存放 IHandler的list和数组 private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>(); private IdleHandler[] mPendingIdleHandlers; private boolean mQuiting; //Thread是否退出 // 判断next()是否因一个非零的超时pollOnce()而处于阻塞等待 private boolean mBlocked; //标志位,表示阻碍是否是由于消息的空target(handler)引起 private int mNextBarrierToken; //native code部分略过 @SuppressWarnings("unused") private int mPtr; // used by native code private native void nativeInit(); private native void nativeDestroy(); private native void nativePollOnce(int ptr, int timeoutMillis); private native void nativeWake(int ptr);
我们来了解一下MessageQueue内部定义的IdleHanlder接口:
这是一个提供给线程,用来阻塞等待更多消息的回调接口。
public static interface IdleHandler { boolean queueIdle(); }
queueIdle()方法会在该消息队列处理完所有消息并且不会有新消息时候调用,返回true则该闲置idlehandler保持活跃,否则(false)移除该idleHandler。当然,如果还有消息在队列中等待,并且这些消息是在接下来的时间才被处理,那么queueIdle()也会被调用。
对于添加和移除idlehandler我们简要略过.
public final void addIdleHandler(IdleHandler handler) { if (handler == null) { throw new NullPointerException("Can't add a null IdleHandler"); } synchronized (this) { mIdleHandlers.add(handler); } } public final void removeIdleHandler(IdleHandler handler) { synchronized (this) { mIdleHandlers.remove(handler); } }
取消息next()
final Message next() { int pendingIdleHandlerCount = -1; //空闲的idleHandler个数 int nextPollTimeoutMillis = 0;//下次取消息的时间 for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands();//刷新等待命令 } nativePollOnce(mPtr, nextPollTimeoutMillis);//更新下次取消息时间 //取消息锁 synchronized (this) { if (mQuiting) {//线程正退出 return null; } // 尝试取下一条消息并返回 final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { //查找下一个不为空且不是异步的消息 do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // 如果当前消息并没到指定时间,则等待nextPollTimeoutMillis 后执行取操作 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { // 取一条消息 mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (false) Log.v("MessageQueue", "Returning message: " + msg); msg.markInUse(); return msg; } } else { // 当没有消息时,下次取操作的时间间隔设置为-1 nextPollTimeoutMillis = -1; } // 如果是首次闲置,则获取需要运行的空闲hanlder数量。闲置的hanlder只有在消息队列为空或者当前时间没有消息被处理的时候等待 if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // 如果没有闲置handler等待,则消息队列进入阻塞等待 mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // 运行闲置handler,我们只有在首次迭代时运行下边这段代码 for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; //释放闲置hanlder boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf("MessageQueue", "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } //重置闲置handler数量 pendingIdleHandlerCount = 0; //当回收闲置handler时候可能有新消息被放进来,所以更新下次取消息时间重新执行 nextPollTimeoutMillis = 0; }}
插入消息enqueueMessage(Message msg, long when)
final boolean enqueueMessage(Message msg, long when) { //如果消息正在被使用或者消息的处理handler为空,都会抛异常 if (msg.isInUse()) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null) { throw new AndroidRuntimeException("Message must have a target."); } boolean needWake; synchronized (this) { if (mQuiting) {//如果线程已退出,则抛出异常 RuntimeException e = new RuntimeException( msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } msg.when = when; Message p = mMessages; if (p == null || when == 0 || when < p.when) { // 如果消息处理时间等于0或者小雨队列头的处理时间,则将该消息插至消息队列头 msg.next = p; mMessages = msg; needWake = mBlocked; } else { //将消息插入对位,通常我们不需要唤醒事件,除非消息队列处在阻塞状态并且这条消息是队列中最早的异步消息 needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } } if (needWake) { nativeWake(mPtr); } return true; }
删除消息removeMessages()
final void removeMessages(Handler h, int what, Object object) { if (h == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && p.what == what && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycle(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && n.what == what && (object == null || n.obj == object)) { Message nn = n.next; n.recycle(); p.next = nn; continue; } } p = n; } } } final void removeMessages(Handler h, Runnable r, Object object) { if (h == null || r == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && p.callback == r && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycle(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && n.callback == r && (object == null || n.obj == object)) { Message nn = n.next; n.recycle(); p.next = nn; continue; } } p = n; } } } final void removeCallbacksAndMessages(Handler h, Object object) { if (h == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycle(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && (object == null || n.obj == object)) { Message nn = n.next; n.recycle(); p.next = nn; continue; } } p = n; } } }
4.4 Handler
Handler是和线程的MessageQueue相关联的Runable对象,用于发送和处理消息。Handlerg和线程及线程的MessageQueue是一一对应的,即每个Handler实例关联一个单一线程和该线程的messagequeue。当您创建一个Handler时,它就绑定到创建它的线程以及对应的消息队列。使用该handler将发送消息到对应消息队列,并由Handler处理取出的消息。
简单来说,handler主要做了两件事:
- 将要处理的数据消息或runnable以消息形式放入消息队列,在指定时间处理;
- 保证运行在多个线程中得消息对象能够在指定线程中被有序处理。
1.先看属性变量:
public class Handler { /* * 标志位,用来检测那些继承于它但不是静态的匿名类、本地类或成员类,这些类可能会导致内存泄露。 */ private static final boolean FIND_POTENTIAL_LEAKS = false; private static final String TAG = "Handler"; final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; final boolean mAsynchronous; IMessenger mMessenger;}
2.再看构造方法:
public Handler() { this(null, false); } public Handler(Callback callback) { this(callback, false); } public Handler(Looper looper) { this(looper, null, false); public Handler(Looper looper, Callback callback) { this(looper, callback, false); } public Handler(boolean async) { this(null, async); }
最后都执行的是这两段构造方法:
- Handler(Callback callback, boolean async)
- 当标志位为true,检测到可能造成内存泄露的类时抛出异常
- 得到当前线程的looper初始化其属性变量
- Handler(Looper looper, Callback callback, boolean async)
- 由传入的参数初始化属性变量
public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & 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( "Can't create handler inside thread that has not called 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; }
3.接着看它的生成Message:
产生消息的方法obtainMessage()是间接调用Message的obtain()方法,尝试从消息池中取已有message实例,便于高效和重复利用。
//基本类似,不再一一列举 public final Message obtainMessage() public final Message obtainMessage(int what) public final Message obtainMessage(int what, Object obj); //利用Message的obtain方法构造消息 public final Message obtainMessage(int what, int arg1, int arg2, Object obj){ return Message.obtain(this, what, arg1, arg2, obj); } //将runnable封装成消息 private static Message getPostMessage(Runnable r) private static Message getPostMessage(Runnable r, Object token) { Message m = Message.obtain(); m.obj = token; m.callback = r; return m; }
4.然后看它的send消息的过程:
handler有提供post(runnable)和sendMessage(message)两种方法。post其实就是通过上边的getPostMessage方法将runnable对象封装成消息发送至消息队列。这些发送消息的方法有:
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } //上述方法都调用sendMessageDelayed()方法 public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
这些方法都转入了sendEmptyMessageAtTime这个方法中去
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); } //还有这个方法 public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); }
sendMessageAtTime在指定时间发送消息,对消息进行有序排队。调用enqueueMessage()方法,该方法又调用消息队列的queue.enqueueMessage()方法。在指定时间更新消息时序。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
发送消息还有一个方法,将消息放在队列首并立即取消息。使用方法sendMessageAtFrontOfQueue
public final boolean sendMessageAtFrontOfQueue(Message msg) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, 0); }
最后looper循环取消息并调用handler的处理方法dispatchMessage 和handleMessage
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } //当message的callback不为空的时候,调用handleCallback private final void handleCallback(Message message) { message.callback.run(); } //这里是个空方法需要子类定义处理逻辑 public void handleMessage(Message msg) { }
当我们实例化一个handler时候,handler会通过mCallback接口来回调我们的handleMessage方法,看一下这个接口:
public interface Callback { public boolean handleMessage(Message msg); }
同时handler也提供了移除回调removeCallbacks 和 移除消息removeMessages方法
//移除回调 public final void removeCallbacks(Runnable r) { mQueue.removeMessages(this, r, null); } public final void removeCallbacks(Runnable r, Object token) { mQueue.removeMessages(this, r, token); } //移除消息 public final void removeMessages(int what) { mQueue.removeMessages(this, what, null); } public final void removeMessages(int what, Object object) { mQueue.removeMessages(this, what, object); } //移除消息和回调 public final void removeCallbacksAndMessages(Object token) { mQueue.removeCallbacksAndMessages(this, token); }
5.综述
以上便是Android中的消息机制的几个核心部分内容和源码概括完了。详细读到这里多少也对整个体系有了点深入了解吧。当然,个人叙述相对有些混乱,建议感兴趣的朋友可以在sdk\sources目录下找到相应源码查看具体详细。
作为补充还是把对应的Handler Looper MessageQueue 和 Message 的.java文件放上来,方便不会关联源码的朋友查看。
Handler/Looper/MessageQueue/Message .java 文件
- Android更新Ui进阶精解(二)
- Android更新Ui进阶精解(一)
- android UI进阶之布局的优化(二)
- android UI进阶之布局的优化(二)
- android UI进阶之布局的优化(二)
- Android进阶(二十四)Android UI---界面开发推荐颜色
- android UI进阶之仿iphone的tab效果(二)
- android UI进阶之仿iphone的tab效果(二)
- android UI进阶之仿iphone的tab效果(二)
- Android进阶(二)-------总结4种线程中操作UI界面的方法
- android UI进阶之仿iphone的tab效果(二)
- android UI进阶之自定义组合控件二
- Android UI (持续更新)
- android UI进阶教程
- android ui进阶教程
- android ui进阶教程
- android 进阶之UI
- 网站开发进阶(二十二)HTML UI知识汇总(更新中...)
- [Practical.Vim(2012.9)].Drew.Neil.Tip99 学习摘要
- 【C语言】输入三个字符串,由小到大排序输出。
- 使用CSDN-markdown编辑器:-)
- 《TCP/IP详解卷1:协议》第4章 ARP:地址解析协议-读书笔记
- Java 对象序列化
- Android更新Ui进阶精解(二)
- NDK开发
- Android之NDK开发
- NDK环境搭建
- 用FrameLayout加OnToucherListener制作View切换动画
- 关于推箱子自动求解源码的若干问题
- Linux---scp、cp命令
- 磁共振梯度回波(gradiant echo)与自旋回波(spin echo)
- 图片轮换