Android消息机制之一---Looper

1.1  Looper

位置:

/frameworks/base/core/java/android/os/Looper.java

 

Looper:循环者的意思,他被设计用来将一个普通线程变成Looper线程,即循环工作的线程。

/*

56     * API Implementation Note:

57     *

58     * This class contains the code required to set up and manage an event loop

59     * based on MessageQueue.  APIs that affect the state of the queue should be

60     * defined on MessageQueue or Handler rather than on Looper itself.  For example,

61     * idle handlers and sync barriers are defined on the queue whereas preparing the

62     * thread, looping, and quitting are defined on the looper.

63     */

 

 

Looper类基于MessageQueue(消息队列)来管理一个循环事件。并且这个消息队列的状态是在MessageQueue(消息队列)或者Handler中设置和更改的,并不是在Looper中。也就是说,Looper通过一个由其他类控制的MessageQueue来维持循环。其中MessageQueue已经封装到了Looper中,对于开发者来说,MessageQueue是透明的,直接操作的是Message

如何是一个正常的线程变成Looper线程:

 

public class LooperThread extends Thread {

    @Override

    public void run() {

        // 将当前线程初始化为Looper线程

        Looper.prepare();

       

        // ...其他处理,如实例化handler

       

        // 开始循环处理消息队列

        Looper.loop();

    }

}



通过两行核心代码,普通线程就会变成Looper线程。

Looper.prepare()

Looper.loop()




 

     通过Looper.prepare(),线程中就会出现一个Looper的对象,它内部维护一个消息队列,并且通过prepare()源码我们发现,一个线程只能对应一个Looper对象

其实,将普通线程,变成Looper线程比较简单。接下来,我们看下Looper的源码,分析下它的实现。


// sThreadLocal.get() will return null unless you've called prepare().
68    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();      //每个线程只能有一个Looper对象
69    private static Looper sMainLooper// guarded by Looper.class
70
71    final MessageQueue mQueue//消息队列
72    final Thread mThread//当前线程
73
74    private Printer mLogging;

 

 

每个线程中的Looper对象其实就是一个ThreadLocal,即线程本地存储(TLS)对象。

 

/** Initialize the current thread as a looper.
77      * This gives you a chance to create handlers that then reference
78      * this looper, before actually starting the loop. Be sure to call
79      * {@link #loop()} after calling this method, and end it by calling
80      * {@link #quit()}.
81      */
    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(BooleanquitAllowed);方法是利用TLS来产生Looper对象。

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();  //Looper的Thread指向的是当前的线程
    }

 

Looper的构造方法。

生成MessageQueue;

mThread指向当前线程;

 

 

Looper中的主循环,loop(循环),知道quit()后执行终止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(); //得到当前线程Looper
   if (me == null) {
       throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//得到当前Looper的MQ(消息队列)
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.
    //确定该线程是属于本地进程,不影响Looper理解
   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);
       }
 
      //重要,真正的处理工作借给Message的target,即handler
       msg.target.dispatchMessage(msg);
       if (logging != null) {
           logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
       }
    //ID处理
    // 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);
      }
      //回收Message资源
      msg.recycleUnchecked();
   }
}

 

当Looper调用loop()后,looper线程开始真正的工作。


Looper的其他函数:

myLooper()//获取当前Looper

 

public static @Nullable Looper myLooper() {
      return sThreadLocal.get();
}

 

//getMainLooper()获取application中的主线程的looper

/**
     * Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

 

 

quit()函数;

//一些消息可能还没有提交,在loop处理结束之前

public void quit() {   
     mQueue.quit(false);
}

 

//所有消息都处理结束,并且没有新的消息提交

public void quitSafely() {
     mQueue.quit(true);
}
 

其中android中的Actvity也为一个Looper线程。

Looper 循环者,它设计是用来是一个普通线程变成Looper线程。主要作用是使一个线程不断循环,一旦有新任务则完成新任务,之后继续循环等待下一个任务。

 总结:

1.每个线程有且最多只能有一个Looper对象,它是一个ThreadLocal

2.Looper内部有一个消息队列,loop()方法调用后线程开始不断从队列中取出消息执行

3.Looper使一个线程变成Looper线程。


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值