Android的消息处理机制

在Android系统中,主线程用于处理Window及各种窗口上的输入事件,当然应用程序中的Activity、Broadcast Receiver等也是由主线程来处理。除了主线程之外,往往还有单独运行的线程,通常由开发者自己创建,用来做一些额外的工作,尤其是那种耗时的工作,这就需要Thread的子类来实现。

接口java.lang.Runnable代表着一小段执行的任务,由一个线程去调用执行。Runnable接口只有一个run(),子类将需要完成的任务放在该函数中。问题来了,通常在java.lang.Thread线程中没有消息循环,也就是说,在run函数中,通常是执行完处理之后,意味着流程结束,也就是线程结束。如果需要让线程长期存在去处理某种任务,需要自己写个while(){}循环,在循环中去执行需要完成的任务。在执行的过程中,通常会因为条件不满足而阻塞,条件满足后被唤醒执行。显然这整个过程需要开发者去判断,稍有不慎,将造成严重的后果。

1.简要介绍

Android提供了一种消息处理的机制,调用者将需要处理的任务发送到消息队列后返回,线程不断的从消息队列中读取消息,进行处理。这种消息驱动的方式,让系统中的任务处理变得灵活。因此,不难想象,这整个过程如下图所示,不断的向消息队列发送消息,从消息队列中取消息,并发送来执行。

因此需要如下几个要素:

Ÿ  消息的表示:Message

Ÿ  消息队列:MessageQueue

Ÿ  消息循环:Looper

Ÿ  消息处理:Handler

在介绍Android的消息处理机制之前,我们首先通过一个简单的例子,了解如果一个线程想要实现消息循环应该怎么做,如下是源码中给我们提供的一个例子,如此该线程便成为了一个Looper线程,不断的从消息队列中取消息,并调用mHandler的handleMessage处理消息。

class LooperThread extends Thread {

      public Handler mHandler;

 

      public void run() {

          Looper.prepare();

 

          mHandler = new Handler() {

              public void handleMessage(Message msg) {

                  // process incoming messages here

              }

          };

 

          Looper.loop();//开始循环,从消息队列中取消息,利用Handler去处理

      }

}

 

LooperThread.mHandler.sendMessage(msg);//消息发送

大家现在肯定会有如下疑惑,带着如下问题,我们去看Looper、Handler的源码。

1)      MessageQueue在哪儿?

2)      LooperThread是如何从MessageQueue取消息的?

3)      取到消息之后,是如何发送给mHandler的?

4)      他们之间的对应关系又是怎么样的?

2.Looper

在java层 native层均有Looper的实现,但其作用不一样。

2.1 Java层的Looper

首先来看Java层,其主要作用是将一个线程初始化为一个Looper线程,从MessageQueue中取消息发送给Handler执行。

     /** 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[1]) {

        if (sThreadLocal.get() != null[2]) {

            throw new RuntimeException("Only one Looper may be created per thread");

        }

        sThreadLocal.set(new Looper(quitAllowed));

}

 

    private Looper(boolean quitAllowed) {

        mQueue[3] = new MessageQueue(quitAllowed);

        mThread = Thread.currentThread();

    }

代码很简单,但是需要解释三点:

1)      quitAllowed:是否允许消息队列退出

2)      prepare()会先检查该线程是否已经有了自己的Looper,若有则会抛出异常,即一个线程最多只能有一个Looper。

3)      Looper的构造函数中,新建了一个自己的MessageQueue对象,保存在成员mQueue,在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()[1]; // might block

            if (msg == null[2]) {

                // 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();

        }

}

1)      Looper.loop()调用MessageQueue.next()从自己的消息队列中取出下一个消息,然后调用Handler的dispatchMessage(msg)将消息进行分发处理。其中next()可能会阻塞,例如消息队列为空,或者消息尚未准备好执行等等。

2)      若调用MessageQueue.next()返回空,不意味着消息队列为空,而是意味着此时调用了Looper.quit()。因此,当希望线程退出消息循环时,需要调用Looper.quit()函数。

/**********Looper.java***********/

public void quit() {

        mQueue.quit(false);

}

/***********MessageQueue.java************/

    void quit(boolean safe) {

        ……

            mQuitting = true;

……

    }

    Message next() {

        ……

// Process the quit message now that all pending messages have been handled.

                if (mQuitting) {

                    dispose();

                    return null;

                }

……

    }

Looper.java还有两个重要的函数,用来实现消息同步的,先不赘述,在MessageQueue中详细介绍

public int postSyncBarrier() {

        return mQueue.enqueueSyncBarrier(SystemClock.uptimeMillis());

    }

public void removeSyncBarrier(int token) {

        mQueue.removeSyncBarrier(token);

    }

2.2 Native层的Looper

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值