Android消息机制之Looper

    android中非常重要的一个消息通信机制handler,可以理解为是android进程内部的一种消息通信机制,通过消息队列,提高系统的并发性。

    

   根据上图,可以看出,handler消息队列的核心是looper,其实Looper实质是一个“绑定”到某个线程的无限循环,该循环不停的从消息队列中取出消息,并且分发给该消息对应的target,也就是一个Handler来实际的分发处理该消息。那么我们先来看一看Looper的真实面目。根据代码段来分析

public class Looper{

    private static final String TAG ="Looper";

 

    // sThreadLocal.get() will return nullunless you've called prepare().

    static final ThreadLocal<Looper>sThreadLocal = new ThreadLocal<Looper>();

    private static Looper sMainLooper;  // guarded by Looper.class

 

    final MessageQueue mQueue;

    final Thread mThread;

    volatile boolean mRun;

......

}

   首先looper会初始化一个静态的线程局部变量,那么这个线程局部变量意欲何为呢,下面看一些prepare(......)这个方法

public staticvoid prepare() {

        prepare(true);

    }

 

    private static void prepare(booleanquitAllowed) {

        if (sThreadLocal.get() != null) {

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

        }

        sThreadLocal.set(newLooper(quitAllowed));

    }

 

   根据prepare()方法的代码可以看出,该公共方法会调用Looper类的一个私有的方法prepare(boolean quitAllowed),从这个方法里,我们应该可以看出sThreadLocal这个线程局部变量的作用了,对了,没错,你肯定猜出来啦,就是为了将一个Looper对象绑定到当前线程中,就是为了线程的并发访问,如此简单而已。那么类Looper的构造方法做了什么呢?

   private Looper(boolean quitAllowed) {

        mQueue = new MessageQueue(quitAllowed);

        mRun = true;

        mThread = Thread.currentThread();

    }

   这个方法的主要工作就是生成了一个消息队列的对象,并且初始化mThread为当前进程,那么这个mThread是用来做什么的呢,这个可以根据Looper类的一个公共成员方法getThread()方法来推测,这个方法应该是用于ThreadLocal这个类的内部来使用,可能是作为一个key,来存储Looper对象。

   所以说,当你想在一个线程中绑定一个Looper对象时,肯定要首先调用Looper类的静态公共方法prepare()。那么你可能现在会问了,你不是说,会将一个无限循环绑定到当前线程中,别着急,下面就是了,

public staticvoid loop() {

 ①       final Looper me =myLooper();

        if (me == null) {

            throw new RuntimeException("NoLooper; Looper.prepare() wasn't called on this thread.");

        }

②        final MessageQueuequeue = me.mQueue;

 

        // Make sure the identity of thisthread is that of the local process,

        // and keep track of what that identitytoken actually is.

        Binder.clearCallingIdentity();

        final long ident =Binder.clearCallingIdentity();

 

   ③     for (;;) {

            Message msg = queue.next(); //might block

            if (msg == null) {

                // No message indicates thatthe message queue is quitting.

                return;

            }

 

            // This must be in a localvariable, 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);

            }

 

         ......

 

     ⑤       msg.recycle();

        }

    }

   这又是一个类的静态公共方法,所以对于Looper类来说,当你在某个线程中调用Looper类中的方法时,都是通过类名来调用的,而不是通过Looper的对象来调用,因为生成Looper对象是由prepare这个公共方法在类的内部来实现的。

   从上面的编号1处的代码段可以知道,该方法首先会判断是否可以通过sThreadLocal来获取当前进程的Looper类对象,如果获取失败,则跑出异常,这个异常是说当前进程没有调用Looper.prepare()方法,从这里,我们也可以推断,在一个进程中,prepare方法肯定要在loop()方法之前被调用。

   编号2处的代码段是获取消息队列的对象。

   编号3处的代码则是进入了一个无限的for循环,这个for循环就是从消息队列中取出消息,

   编号4则是这个过程的中心环节了,通过获取msg的target成员变量(也就是一个handler对象),然后通过该变量调用disapatchMessage(msg)来分发处理消息。

   编号5则是用于回收处理过的消息对象。

以上简单分析了Looper的实现原理,下面一节,将会进一步分析Handler的消息机制。由于个人水平有限,如有错误,敬请指正!



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值