美文网首页Android札记Android 轮子android
Android更新Ui进阶精解(二)

Android更新Ui进阶精解(二)

作者: Qiaoidea | 来源:发表于2015-05-17 17:12 被阅读646次

    《代码里的世界》

    用文字札记描绘自己 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);
        }
    

    最后都执行的是这两段构造方法:

    1. Handler(Callback callback, boolean async)
      • 当标志位为true,检测到可能造成内存泄露的类时抛出异常
      • 得到当前线程的looper初始化其属性变量
    2. 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进阶精解(二)

        本文链接:https://www.haomeiwen.com/subject/lnakqttx.html