4.线程Looper

Looper用来使一个普通线程变成一个looper线程,所谓looper就是一个循环工作的线程。

public class LooperThread extends Thread {
    @Override
    public void run() {
        // 将当前线程初始化为Looper线程  
        Looper.prepare();
        // ...其他处理,如实例化handler  
        // 开始循环处理消息队列  
        Looper.loop();
    }
}

1.Looper.prepare();
你的线程中有一个Looper对象,它的内部维护了一个消息队列MQ。注意,一个Thread只能有一个Looper对象,为什么呢?咱们来看源码。
looper的源码

public class Looper {
    // 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象  
    private static final ThreadLocal sThreadLocal = new ThreadLocal();
    // Looper内的消息队列  
    final MessageQueue mQueue;
    // 当前线程  
    Thread mThread;
    // 。。。其他属性
    // 每个Looper对象中有它的消息队列,和它所属的线程  
    private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }
    // 我们调用该方法会在调用线程的TLS中创建Looper对象  
    public static final void prepare() {
        if (sThreadLocal.get() != null) {
            // 试图在有Looper的线程中再次创建Looper将抛出异常  
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
    // 其他方法  
}

通过源码,prepare()背后的工作方式一目了然,其核心就是将looper对象定义为ThreadLocal。
2.looper.loop()
调用loop方法后,Looper线程就开始真正工作了,它不断从自己的MQ中取出队头的消息(也叫任务)执行。其源码分析如下:

public static final void loop() {
    Looper me = myLooper();  //得到当前线程Looper  
    MessageQueue queue = me.mQueue;  //得到当前looper的MQ  
    // 这两行没看懂= = 不过不影响理解  
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();
    // 开始循环  
    while (true) {
        Message msg = queue.next(); // 取出message  
        if (msg != null) {
            if (msg.target == null) {
                // message没有target为结束信号,退出循环  
                return;
            }
            // 日志。。。  
            if (me.mLogging!= null) me.mLogging.println(
                    ">>>>> Dispatching to " + msg.target + " "
                            + msg.callback + ": " + msg.what
            );
            // 非常重要!将真正的处理工作交给message的target,即后面要讲的handler  
            msg.target.dispatchMessage(msg);
            // 还是日志。。。  
            if (me.mLogging!= null) me.mLogging.println(
                    "<<<<< Finished to    " + msg.target + " "
                            + msg.callback);
            // 下面没看懂,同样不影响理解  
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf("Looper", "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.recycle();
        }
    }
}

除了prepare()和loop()方法。Looper类还提供了一些有用的方法,比如
Looper.myLooper()的到当前线程的looper对象:

public static final Looper myLooper() {
    // 在任意线程调用Looper.myLooper()返回的都是那个线程的looper  
    return (Looper)sThreadLocal.get();
}

getThread()得到looper对象所属线程:

public Thread getThread() {
    return mThread;
}

quit()方法结束looper循环:

public void quit() {
    // 创建一个空的message,它的target为NULL,表示结束循环消息  
    Message msg = Message.obtain();
    // 发出消息  
    mQueue.enqueueMessage(msg, 0);
}

Looper的基本总结
1.每一个线程有且最多只能有一个Looper对象,它是一个ThreadLocal
2.Looper内部有一个消息队列。loop()方法调用后线程开始不断从队列中取出消息执行
3.Looper使一个线程变成Looper线程

你可能感兴趣的:(4.线程Looper)