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

 

posted on 2015-08-09 22:32  Joyfulmath  阅读(959)  评论(0编辑  收藏  举报

导航