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

  • 相关阅读:
    AtCoder Grand Contest 001
    在AT151上面测试串口通讯
    i2c tools 使用
    STM32CUBEF4 实现USB 虚拟串口
    SPI总线工作模式
    树莓派3b+ wifi无线连接
    树莓派开机运行Python脚本 控制LED灯闪烁
    树莓派 使用python来操作GPIO 控制LED灯
    解决树莓派新版系统 ssh连接不了问题
    C# textBox控件只允许为数字和小数点并且提取出这个数字
  • 原文地址:https://www.cnblogs.com/deman/p/4711402.html
Copyright © 2011-2022 走看看