博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[Android] android的消息队列机制
阅读量:6988 次
发布时间:2019-06-27

本文共 22745 字,大约阅读时间需要 75 分钟。

hot3.png

android下的线程,Looper线程,MessageQueue,Handler,Message等之间的关系,以及Message的send/post及Message dispatch的过程。

Looper线程

我 们知道,线程是进程中某个单一顺序的控制流,它是内核做CPU调度的单位。那何为Looper线程呢?所谓Looper线程,即是借助于Looper和 MessageQueue来管理控制流的一类线程。在android系统中,application的主线程即是借助于Looper和 MessageQueue来管理控制流的。其实,不仅仅只有主线程可以用Looper和MessageQueue来管理控制流,其他的线程也一样可以。我 们可以先看一下android source code的注释中给出的一种Looper线程的实现方式:

package com.example.messagequeuedemo;import android.os.Handler;import android.os.Looper;import android.util.Log;public class LooperThread extends Thread {    public static final String TAG = MainActivity.TAG;    private static final String CompTAG = "LooperThread";    public Handler mHandler;    @Override    public void run() {        Log.d(TAG, CompTAG + ": LooperThread=>run");        Looper.prepare();        mHandler = new Handler() {            public void handleMessage(android.os.Message msg) {                Log.d(TAG, CompTAG + ": LooperThread=>Handler=>handleMessage");                // process incoming message here            }        };        Looper.loop();    }}

可以看到,就是在线程的run()方法中,调用Looper.prepare() 做一些初始化,然后创建一个Handler对象,最后执行Looper.loop()即开始了整个的事件循环。就是这么的简单,一个可以使用消息队列来管 理线程执行流程的Looper 线程就创建好了。

接着我们来看一下,神秘的Looper.prepare()到底都干了些什么事情:

 // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal
 sThreadLocal = new ThreadLocal
();/** Initialize the current thread as a looper.  * This gives you a chance to create handlers that then reference  * this looper, before actually starting the loop. Be sure to call  * {@link #loop()} after calling this method, and end it by calling  * {@link #quit()}.  */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));}private Looper(boolean quitAllowed) {    mQueue = new MessageQueue(quitAllowed);    mRun = true;    mThread = Thread.currentThread();}

可 以看到,它做的事情就是为当前的线程创建了一个Looper对象,并存储在一个静态的线程局部变量中。在Looper的构造函数中创建了 MessageQueue,同时Looper会引用到当前的线程,并将一个表示状态的变量mRun设置为true。对于此处的线程局部变量 sThreadLocal,可以理解为就是一个HashMap,该HashMap中存放的数据其类型为Looper,而HashMap的key则 Thread.currentThread()。

启动Looper线程就和启动普通的线程一样,比如:

public class MainActivity extends Activity {    public static final String TAG = "MessageQueueDemo";    private static final String CompTAG = "MainActivity";    private LooperThread mLooperThread;    @Override    protected void onCreate(Bundle savedInstanceState) {        Log.d(TAG, CompTAG + ": MainActivity=>onCreate");        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mLooperThread = new LooperThread();        mLooperThread.start();    }

同样是new一个Thread对象,然后执行该对象的start()方法。

其实Looper线程有两种,一种就是我们上面看到的那种普通的Looper线 程,另外一种则是main loop线程,创建前者使用我们前面看到的Looper.prepare()方法,而要创建后者,我们则可以使用 Looper.prepareMainLooper()方法。可以看一下Looper.prepareMainLooper()的实现:

/** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself.  See also: {@link #prepare()} */public static void prepareMainLooper() {    prepare(false);    synchronized (Looper.class) {        if (sMainLooper != null) {            throw new IllegalStateException("The main Looper has already been prepared.");        }        sMainLooper = myLooper();    }}

比较特别的地方即在于,此处调用prepare()方法传进去的参数为false,即表示这个Looper不能够被quit掉。其他倒是基本一样。整个android系统中,调用到prepareMainLooper()方法的大概有两处:

/frameworks/base/services/java/com/android/server/H A D    SystemServer.java    94 Looper.prepareMainLooper();/frameworks/base/core/java/android/app/H A D    ActivityThread.java    5087 Looper.prepareMainLooper();

一处在ServerThread的run()方法中,用于为system server主线程初始化消息队列等,另外一处在ActivityThread的run()方法中,自然即是创建android app主线程的消息队列了。

通过消息与Looper线程交互

那 Looper线程的特别之处究竟在哪里呢?如前所述,这种线程有一个Looper与之关联,这种线程会使用消息队列,或者称为事件循环来管理执行的流程。 那这种特别之处又如何体现呢?其他线程可以向此类线程中丢消息进来,当然此类线程本身也可以往自己的消息队列里面丢消息,然后在事件循环中,这种事件会得 到有效的处理。那究竟要如何往Looper线程的消息队列中发送消息呢?

回忆我们前面创建Looper线程的那个code,我们不是有创建出来一个Handler嘛。没错,我们就是通过Handler来向Looper线程的MessageQueue中发送消息的。可以看一下code的写法。先是LooperThread的写法:

package com.intel.helloworld;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.util.Log;public class LooperThread extends Thread {    private static final String TAG = MainActivity.TAG;    private static final String CompTAG = "LooperThread";    public Handler mHandler;    @Override    public void run() {        Log.d(TAG, CompTAG + ": " + "LooperThread-->run");        Looper.prepare();        mHandler = new Handler() {            @Override            public void handleMessage(Message msg) {                // process incoming message                Log.d(TAG, CompTAG + ": " + "Handler-->handleMessage, msg.what = " + msg.what);            }        };        Looper.loop();    }    public Handler getHandler() {        return mHandler;    }}

然后是向Looper线程发送消息的部分的写法:

package com.intel.helloworld;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.app.Activity;import android.util.Log;import android.view.Menu;public class MainActivity extends Activity {    public static final String TAG = "LifecycleDemoApp";    private static final String CompTAG = "MainActivity";        public static final int MESSAGE_WHAT_CREATE = 1;    public static final int MESSAGE_WHAT_START = 2;    public static final int MESSAGE_WHAT_RESUME = 3;    public static final int MESSAGE_WHAT_PAUSE = 4;    public static final int MESSAGE_WHAT_STOP = 5;    public static final int MESSAGE_WHAT_DESTROY = 6;    LooperThread mThread;    @Override    protected void onCreate(Bundle savedInstanceState) {        Log.d(TAG, CompTAG + ": " + "Activity-->onCreate");        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mThread = new LooperThread();        mThread.start();    }    @Override    protected void onStart() {        Log.d(TAG, CompTAG + ": " + "Activity-->onStart");        super.onStart();        Handler handler = mThread.mHandler;        Message msg = Message.obtain();        msg.what = MESSAGE_WHAT_START;        handler.sendMessage(msg);    }        @Override    protected void onResume() {        Log.d(TAG, CompTAG + ": " + "Activity-->onResume");        super.onResume();        Handler handler = mThread.mHandler;        Message msg = Message.obtain();        msg.what = MESSAGE_WHAT_RESUME;        handler.sendMessage(msg);    }        @Override    protected void onPause() {        Log.d(TAG, CompTAG + ": " + "Activity-->onPause");        super.onPause();        Handler handler = mThread.mHandler;        Message msg = Message.obtain();        msg.what = MESSAGE_WHAT_PAUSE;        handler.sendMessage(msg);    }        @Override    protected void onStop() {        Log.d(TAG, CompTAG + ": " + "Activity-->onStop");        super.onStop();        Handler handler = mThread.mHandler;        Message msg = Message.obtain();        msg.what = MESSAGE_WHAT_STOP;        handler.sendMessage(msg);    }    @Override    protected void onDestroy() {        Log.d(TAG, CompTAG + ": " + "Activity-->onDestroy");        super.onDestroy();        Handler handler = mThread.mHandler;        Message msg = Message.obtain();        msg.what = MESSAGE_WHAT_DESTROY;        handler.sendMessage(msg);    }    @Override
 public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        return true;    }    @Override    protected void onSaveInstanceState(Bundle outState) {        Log.d(TAG, CompTAG + ": " + "Activity-->onSaveInstanceState");        super.onSaveInstanceState(outState);    }}

向一个Looper线程发送消息的过程,基本上即是,调用Message.obtain()或Handler.obtainMessage()获取一个Message对象->设置Message->调用 Looper线程中创建的Handler对象来发送消息。

Handler 究竟是如何知道要向哪个MessageQueue中发送消息呢,从前面的code中,我们找不到任何将Handler与特定的MessageQueue关 联起来的代码,这究竟是怎么回事呢?这也是我们强调要使用Looper线程中创建的Handler对象来向该Looper线程中发送消息的原因。我们可以 看一下Handler对象构造的过程:

/** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */public Handler() {    this(null, false);}/** * Constructor associates this handler with the {@link Looper} for the * current thread and takes a callback interface in which you can handle * messages. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. * * @param callback The callback interface in which to handle messages, or null. */public Handler(Callback callback) {    this(callback, false);}/** * Use the provided {@link Looper} instead of the default one. * * @param looper The looper, must not be null. */public Handler(Looper looper) {    this(looper, null, false);}/** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. */public Handler(Looper looper, Callback callback) {    this(looper, callback, false);}/** * Use the {@link Looper} for the current thread * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with represent to synchronous messages.  Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier long)}. * * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */public Handler(boolean async) {    this(null, async);}/** * Use the {@link Looper} for the current thread with the specified callback interface * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with represent to synchronous messages.  Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier long)}. * * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */public Handler(Callback callback, boolean async) {    if (FIND_POTENTIAL_LEAKS) {        final Class
 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;}

可以看到,很简单,是通过Looper.myLooper()获取到当前线程的 Looper对象,并与相关的MessageQueue等关联起来的。这也是前面我们在实现Looper线程时,要在其run方法中创建一个public 的Handler的依据。当然,我们也可以在构造Handler对象时,显式地使其与特定的Looper对象关联起来。

Handler提供了两组函数用于向一个Looper线程的MessageQueue中发送消息,分别是postXXX()族和sendXXX()族。可以先看一下sendXXX()族的实现:

/** * Pushes a message onto the end of the message queue after all pending messages * before the current time. It will be received in {@link #handleMessage}, * in the thread attached to this handler. *   * @return Returns true if the message was successfully placed in to the  *         message queue.  Returns false on failure, usually because the *         looper processing the message queue is exiting. */public final boolean sendMessage(Message msg){    return sendMessageDelayed(msg, 0);}/** * Sends a Message containing only the what value. *   * @return Returns true if the message was successfully placed in to the  *         message queue.  Returns false on failure, usually because the *         looper processing the message queue is exiting. */public final boolean sendEmptyMessage(int what){    return sendEmptyMessageDelayed(what, 0);}/** * Sends a Message containing only the what value, to be delivered * after the specified amount of time elapses. * @see #sendMessageDelayed(android.os.Message, long)  *  * @return Returns true if the message was successfully placed in to the  *         message queue.  Returns false on failure, usually because the *         looper processing the message queue is exiting. */public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {    Message msg = Message.obtain();    msg.what = what;    return sendMessageDelayed(msg, delayMillis);}/** * Sends a Message containing only the what value, to be delivered  * at a specific time. * @see #sendMessageAtTime(android.os.Message, long) *   * @return Returns true if the message was successfully placed in to the  *         message queue.  Returns false on failure, usually because the *         looper processing the message queue is exiting. */public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {    Message msg = Message.obtain();    msg.what = what;    return sendMessageAtTime(msg, uptimeMillis);}/** * Enqueue a message into the message queue after all pending messages * before (current time + delayMillis). You will receive it in * {@link #handleMessage}, in the thread attached to this handler. *   * @return Returns true if the message was successfully placed in to the  *         message queue.  Returns false on failure, usually because the *         looper processing the message queue is exiting.  Note that a *         result of true does not mean the message will be processed -- if *         the looper is quit before the delivery time of the message *         occurs then the message will be dropped. */public final boolean sendMessageDelayed(Message msg, long delayMillis){    if (delayMillis < 0) {        delayMillis = 0;    }    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}/** * Enqueue a message into the message queue after all pending messages * before the absolute time (in milliseconds) uptimeMillis. * The time-base is {@link android.os.SystemClock#uptimeMillis}. * You will receive it in {@link #handleMessage}, in the thread attached * to this handler. *  * @param uptimeMillis The absolute time at which the message should be *         delivered, using the *         {@link android.os.SystemClock#uptimeMillis} time-base. *          * @return Returns true if the message was successfully placed in to the  *         message queue.  Returns false on failure, usually because the *         looper processing the message queue is exiting.  Note that a *         result of true does not mean the message will be processed -- if *         the looper is quit before the delivery time of the message *         occurs then the message will be dropped. */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);}/** * Enqueue a message at the front of the message queue, to be processed on * the next iteration of the message loop.  You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * This method is only for use in very special circumstances -- it * can easily starve the message queue, cause ordering problems, or have * other unexpected side-effects. *   * @return Returns true if the message was successfully placed in to the  *         message queue.  Returns false on failure, usually because the *         looper processing the message queue is exiting. */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);}private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {    msg.target = this;    if (mAsynchronous) {        msg.setAsynchronous(true);    }    return queue.enqueueMessage(msg, uptimeMillis);}

绕来绕去,最终都是调用MessageQueue的 enqueueMessage()方法来将一个Message放入一个MessageQueue中。值得注意的是,在 Handler.enqueueMessage()中,会将Message的target设置为this,这实际上是决定了Looper的消息循环中,在 dispatch/handle message时将会使用的Handler。即,在default情况下,处理message的那个handler也将会是发送此message的 handler。

Handler实际的职责,并不像它的名称所显示的那样,其实它不仅仅是处理message,它还负责发送Message给线程的MessageQueue。

再来看一下MessageQueue的enqueueMessage()方法的code:

boolean enqueueMessage(Message msg, long when) {    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) {            // New head, wake up the event queue if blocked.            msg.next = p;            mMessages = msg;            needWake = mBlocked;        } else {            // Inserted within the middle of the queue.  Usually we don't have to wake            // up the event queue unless there is a barrier at the head of the queue            // and the message is the earliest asynchronous message in the queue.            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;}

整个将Message放入MessageQueue的算法也还算比较清晰简洁,并 没有什么太绕的地方。此处我们可以一览MessageQueue中保存Messages的结构,即,MessageQueue用一个单向链表来保存所有的 Message,而链表中各个Message则按照其请求的执行时间先后来排列。

向Looper 线程的MessageQueue中发送消息的另外一族方法postXXX(),其实现同前面的sendXXX()族方法也大同小异啦:

/** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is * attached. * * @param r The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the *         message queue.  Returns false on failure, usually because the *         looper processing the message queue is exiting. */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;}

Post的message,其callback将是传入的Runnable对象,其他就与send的message一样了。

消息队列中消息的处理

消息队列中的消息是在Looper.loop()中被处理的:

/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the 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();    }}

这个函数会调用Handler的dispatchMessage()方法来处理消息,其实也就是msg.target对象的dispatchMessage()方法。 此外我们可以看到,在Looper.loop()方法的末尾recycle了从MessageQueue中取出的已经dispatch的消息。从而,我们 需要通过Handler向一个Looper线程的MessageQueue中发送消息时,我们只要obtain一个Message然后发送就好了,而不需 要自己手动去recycle,这些事情将会由Looper来帮助我们完成。接着来看Handler. dispatchMessage()的实现:

/** * Handle system messages here. */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(msg),否则的话会依据Handler的mCallback是否为空来确定是否要执行 mCallback.handleMessage(msg),并执行Handler的handleMessage(msg)。Handler的handleMessage()方法通常需要override,来实现消息处理的主要逻辑。而mCallback则使得开发者可以比较容易的添加一种对Message做一些额外检测的机制,以提升消息处理的效率。

接着我们看一下,Handler.handleCallback(msg)的实现:

private static void handleCallback(Message message) {    message.callback.run();}

转载于:https://my.oschina.net/u/242041/blog/202731

你可能感兴趣的文章
Mysql GTID 模式详解
查看>>
es6函数总结
查看>>
Nodejs--readline(逐行读取)
查看>>
QT创建与QT无关的纯C++程序和动态/静态库
查看>>
为网建公司注入专业前端力量
查看>>
Vbox下虚拟机linux系统安装tomcat
查看>>
Mysql 多表合并统计
查看>>
maven引入jar包问题导致项目无法启动,感叹号
查看>>
那些年,阿里巴巴技术男神们写的书!
查看>>
我一个理科生造的AI,怎么就去做历史高考题了呢?
查看>>
Fragment之软件主页面制作
查看>>
properties文件读写自己写的方法
查看>>
Flutter 构建完整应用手册-列表
查看>>
chrome 实用调试技巧
查看>>
http升级https
查看>>
并查集(Union-Find)算法介绍
查看>>
MySQL主从配置
查看>>
8.6 管道符和作业控制
查看>>
网页音乐播放器
查看>>
java实现的web网络书店
查看>>