zoukankan      html  css  js  c++  java
  • 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();
            }
        }
    loop
        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();
            }
        }
    loop

    这里有几个关键点:

     Message msg = queue.next(); // might block

    首先,这句之前有过分析,就是当消息队列没有消息的时候,会block住,直到有消息传过来。

     msg.target.dispatchMessage(msg);

    每条消息只有一个处理位置,就是发送他的handler

     msg.recycle();

    消息结束后释放,这样整个消息池就可以循环使用了。

    可以说android的消息机制是参考的许多成熟的消息机制的基础上,创建而成的,有位难得的是,

    他不仅仅是操作系统的使用,更是给我们android 应用开发者使用的一套工具。

    学习android源码,对我们自己搭建消息机制有很大的借鉴作用。

    参考:

    1.《深入理解android内核设计思想》林学森

    2.《Android内核剖析》

    相关文章:

    android 进程/线程管理(一)----消息机制的框架

    android 进程/线程管理(二)----关于线程的迷思

    android 进程/线程管理(三)----Thread,Looper / HandlerThread / IntentService

  • 相关阅读:
    heat模板
    Leetcode812.Largest Triangle Area最大三角形面积
    Leetcode812.Largest Triangle Area最大三角形面积
    Leetcode811.Subdomain Visit Count子域名访问计数
    Leetcode811.Subdomain Visit Count子域名访问计数
    Leetcode806.Number of Lines To Write String写字符串需要的行数
    Leetcode806.Number of Lines To Write String写字符串需要的行数
    Leetcode819.Most Common Word最常见的单词
    Leetcode819.Most Common Word最常见的单词
    Leetcode783.Minimum Distance Between BST Nodes二叉搜索树结点最小距离
  • 原文地址:https://www.cnblogs.com/deman/p/4711402.html
Copyright © 2011-2022 走看看