Android消息处理机制

在Android系统中,关于消息的处理几乎随处可见。提到消息处理,很自然就会想到消息的发送,消息的存储以及消息的处理这三个方面。

Android系统的消息机制与thread,looper,handler,messagequeue,message这几个类是分不开的,此外还有一个runnalbe类,其实,它最终也会被封装为message。下面首先介绍这几个类以及他们之间的关系,然后按照消息的发送,消息的存储,以及消息的处理来分析。

一、各个对象的简单介绍

thread:在多线程运行环境里,代码段的执行都是线程相关的,中断处理例程除外,它是工作于中断上下文的。Android基于linux,linux本身支持多线程。而我们的looper,handler,messagequeue,message这些对象都是寄宿在某个线程里面的。搞清楚这一点也有利于我们后面理解handler的处理到底是在哪个线程里完成的。

looper:顾名思义,实现一个循环动作。因为通常我们在实现一个线程时会让它做一个无限循环,在循环中处理各种不同的事务。looper的作用就是实现宿主线程的消息循环,后面的代码分析中会看到这一点。它负责从messagequeue中取出消息,然后根据消息指定的handler或者callback来处理这条消息。

messagequeue:消息队列就是存储消息的地方,它利用链表的方法来管理消息,looper就是从这里来获取消息的。

message:单条的消息。里面包含了消息类型,参数,标志位和处理者等等信息,后面代码分析中会详细讲到。

runnable:被封装成消息后发送到消息队列,最终会调用到它的run()方法。

相关的源文件:

HandlerThread.java(继承自java.lang.thread类)

Looper.java

MessageQueue.java

Message.java

Runnable.java


二、代码分析(以Audioservice.java中的AudioHandler为例)

首先看看我们的信使message是如何定义的:

public final class Message implements Parcelable {
    /**
     * User-defined message code so that the recipient can identify 
     * what this message is about. Each {@link Handler} has its own name-space
     * for message codes, so you do not need to worry about yours conflicting
     * with other handlers.
     */
    public int what;

    public int arg1; 

    public int arg2;

    public Object obj;

    /**
     * Optional Messenger where replies to this message can be sent.  The
     * semantics of exactly how this is used are up to the sender and
     * receiver.
     */
    public Messenger replyTo;

    /*package*/ int flags;

    /*package*/ long when;
    
    /*package*/ Bundle data;
    
    /*package*/ Handler target;     
    
    /*package*/ Runnable callback;   
    
    // sometimes we store linked lists of these things
    /*package*/ Message next;
比较重要的几个变量都标识出来了,what用来对消息进行分类,通常在handler中处理时会使用switch(what) case what:来处理.arg1和arg2就是消息里的参数,作什么用可以自行定义。flags用来指出消息是否在使用中,是否为异步消息。when用来指明消息何时被处理,这样就使消息的处理更加灵活了。handler就是消息的处理者。callback是消息处理的另一种方式,当消息中指定了callback,则直接调用callback的run()方法来处理消息,不会再交给handler处理。等分析到后面这一点就会很清晰了。


再来看看thread是如何创建的:

在AudioService的构造函数中(AudioService是在System Server中实例化的,可以参考Android启动流程),调用

    public AudioService(Context context) {
        mContext = context;
        ……
        createAudioSystemThread();
        ……
}

    private void createAudioSystemThread() {
        mAudioSystemThread = new AudioSystemThread();
        mAudioSystemThread.start();
        waitForAudioHandlerCreation();
    }

首先创建一个AudioSystemThread,继承自Thread类(handlerthread也是继承这个类,可以认为AudioSystemThread只是给handlerthread另取了个名字),在调用start之后就会进入它的run()方法,通常,run()里面都会有一个无限循环,我们平时创建线程的时候大多数都是这么使用的,在线程里面做无限循环来处理事情。

    /** Thread that handles native AudioSystem control. */
    private class AudioSystemThread extends Thread {
        AudioSystemThread() {
            super("AudioService");
        }

        @Override
        public void run() {
            // Set this thread up so the handler will work on it
            Looper.prepare();

            synchronized(AudioService.this) {
                mAudioHandler = new AudioHandler();

                // Notify that the handler has been created
                AudioService.this.notify();
            }

            // Listen for volume change requests that are set by VolumePanel
            Looper.loop();
        }
    }

在这个里面,thread已经创建好了,几大角色同时登场, looper出现了, handler也有了,还有message和messagequeue不见踪影。接着看:

    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
在prepare的时候new了一个looper对象了,看看looper的构造函数:

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mRun = true;
        mThread = Thread.currentThread();
    }

到现在为止,另一个重要角色MessageQueue也出现了,最后在run()函数中调用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();
        }
    }

这里面有一个for无限循环,上面也提过,一般我们创建一个线程的时候会利用无限循环来处理事务,这个无限循环就是在AudioSystemThread的run()函数中。looper的循环也不复杂,它要做的事情就是从messagequeue中取出消息,然后调用消息指定的target的dispatchMessage()函数。

还记得上面说过这个target其实就是一个handler,自然dispatchMessage()就是在handler中定义的:

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
从上面可以看出,主要有三个执行分支,如果定义了callback,那么就调用handleCallback()来处理消息,handleMessage不会执行,这个callback其实是一个Runnable实例,它是一个接口类,在使用它的时候,最终会调用它的run()函数;如果没有定义callback,那么就会走到else分支,如果定义了mCallback,就会调用它的handleMessage()来处理,mCallback是什么呢?从它的成员函数也大概能猜到也是一个handler,怎么来的?在后面handler的构造函数中就会看到;如果没有定义mCallback或者handleMessage()返回值为0,则调用targe,即当前实例handler的handleMessage()。

handler的构造函数有4个:

public Handler(){
……
mLooper = Looper.myLooper();
……
mQueue = mLooper.mQueue;
mCallback = null;
}

public Handler(Callback callback){
……
mLooper = Looper.myLooper();
……
mQueue = mLooper.mQueue;
mCallback = callback;
}

public Handler(Looper looper) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = null;
}

public Handler(Looper looper, Callback callback) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
}

在创建handler时,如果没有指定looper,那么这个looper就是当前线程的looper,之后looper取出消息并调用handler的handleMessage()方法来处理消息时,都是运行在looper所在的线程上下文中。如果指令了looper,则消息的处理会在指定的looper所在线程上下文中进行。所以,looper是线程相关的,looper决定了消息在哪个线程里处理。

在实现一个handler时,handleMessage是需要用户根据自己的需要重写的一个函数,例如上面的AudioHandler:

        @Override
        public void handleMessage(Message msg) {

            switch (msg.what) {

                case MSG_SET_DEVICE_VOLUME:
                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
                    break;

                case MSG_SET_ALL_VOLUMES:
                    setAllVolumes((VolumeStreamState) msg.obj);
                    break;

                case MSG_PERSIST_VOLUME:
                    persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2);
                    break;


至此,各个对象基本介绍完了。而且关于消息的处理上面也有说过,looper通过queue.next获取消息,然后调用handler的dispatchMessage()来处理消息,但是消息从何而来呢?下面就来说说消息的发送:

    当我们需要handler来完成某件事情时,首先当然是要往消息队列里发送消息,看看AudioHandler的实现:

                // Post message to set system volume (it in turn will post a message
                // to persist).
                sendMsg(mAudioHandler,
                        MSG_SET_DEVICE_VOLUME,
                        SENDMSG_QUEUE,
                        device,
                        0,
                        streamState,
                        0);
            }
这种方式是直接发送消息,事先并不构建消息实例,消息实例的构造放在这种类型的sendMsg()函数中(sendMsg也有很多个重载同名函数):

    private static void sendMsg(Handler handler, int msg,
            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {

        if (existingMsgPolicy == SENDMSG_REPLACE) {
            handler.removeMessages(msg);
        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
            return;
        }

        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
    }

创建message的接口就是这个obtainMessage():

    public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
    {
        return Message.obtain(this, what, arg1, arg2, obj);
    }

紧接着看Message类的obtain:

    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;
    }
 
public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
消息的target就是传递进来的handler。
前面都是在说消息是如何创建出来的,现在接着发送消息的地方来分析:

    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
            msg.target = this;
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }
直接往队列里提交一条消息。接下来looper就会取出该消息并处理。


还有runnable没有说到,通常,runnable是这样使用的:

handler.post(new Runnable() {
       public void run() {
           mCallback.run(Future2Task.this);
       }
});
调用handler的post接口,在里面实例化一个runnable对象,重写它的run()函数。

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }
将message的callback赋值为r,这样,在前面的dispatchMessage()中,就会调用handlecallback(m)了:

    private static void handleCallback(Message message) {
        message.callback.run();
    }
非常简单,直接调用run()函数。


三、总结

1.looper是线程相关的,一个线程最多只能创建一个looper,前面的分析中没有说,仔细研究looper的创建就会发现这一点。

2.handler的消息发往哪个looper,消息就会在looper的那个线程中得到处理。在构造handler的时候,如果没有指定looper,那么默认就是在创建handler对象的 线程中处理,如果指定了另外一个线程的looper,那么消息就在另外一个looper所在线程中处理。

3.looper从messagequeue中获取消息时,如果没有消息会睡眠等待,这是通过native层的进程通信FIFO实现的。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值