消息循环机制及其原理

一、什么是消息循环

消息循环概述:Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环,通过消息循环可实现线程间通信。在Android线程内,可以通过消息循环的机制以队列的方式实现消息的发送,处理等工作

作用:线程间通信

涉及到的核心类

Message:消息的实体的封装

Handler:消息的发送和处理

Looper:消息循环的核心,管理消息队列,实现与当前线程绑定

MessageQueue:消息队列

二、消息循环的过程

消息循环可以分为两部分来讲

  1. 给线程开启消息循环
class WorkThread extends Thread {  
    public Handler mHandler;  
    public void run() {  
        Looper.prepare();  
        mHandler = new Handler() {  
            public void handleMessage(Message msg) {  
                // 处理收到的消息  
            }  
        };  
        Looper.loop();  
    }  
} 
WorkThread myWorkThread = new MyThread2();
myWorkThread.start();

  1. 创建Message,并发送Message,处理Message
Message msg = Message.obtain();
msg.what = what;
msg.obj = strMsg;
myWorkThread.mHandler.sendMessage(msg);

二、消息循环的原理

开启线程的消息循环

如上代码,就开始了WorkThread线程的消息循环,在主线程或者其他子线程,就可以通过WorkThread.mHandler向WorkThread线程发送Message,并且由handleMessage最终处理Message

我们按照代码的步骤来看主要就是做了3个步骤

  1. Looper.prepare()
  2. new Handler()
  3. Looper.loop()
1. Looper.prepare()

static final ThreadLocal sThreadLocal = new ThreadLocal();
final MessageQueue mQueue;
final Thread mThread;

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) {
    //初始化了MessageQueue
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

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

代码很简单,可以看出prepare()就是

  1. new了一个Looper对象,同时初始化了MessageQueue。
  2. 把该Looper对象放入了创建它的当前线程的ThreadLocal里,建立Looper与创建它的线程的关联(ThreadLocal不理解的同学,可以先查看一些ThreadLocal的资料)。可以理解为Looper成为了创建它的当前线程的一个本地变量

放到前面代码里,就是为WorkThread线程创建了一个本地变量Looper,可以在WorkThread线程中用Looper.myLooper()来获取该Looper对象

2. 创建Handler

我们来看下Handler的构造函数

public Handler() {
    this(null, false);
}

public Handler(Looper looper) {
    this(looper, null, false);
}

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());
        }
    }
    //获取创建线程的Looper
    mLooper = Looper.myLooper();
    //没有Looper,则直接抛出异常
    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;
}

由上面代码可以看出
new Handler()的时候必须先给handler指定一个Looper(在主线程中不需要指定,因为主线程的消息循环在程序启动时就已经开启了),否则会抛出异常,即Handler使依附于Looper的

3. Looper.loop()
public static void loop() {
    ......//省略
    for (;;) {
        Message msg = queue.next(); //可能阻塞 MessageQueue中取出msg
        ......//省略
        msg.target.dispatchMessage(msg);//分发msg
        ......//省略
        msg.recycleUnchecked();//回收msg
    }
}

代码比较长,我们挑核心来看,其实主要就是做了三件事

  1. 开启了一个死循环for(;;)
  2. 从MessageQueue中取出Message
  3. 分发Message
  4. 回收Message

由于这是一个死循环,这个循环会不停的调用queue.next(),从MessageQueue中取出Message来处理,然后调用dispatchMessage来分发Message,最后回收msg

这样一个线程的消息循环就建立了,其他线程就可以通过该线程的handler与该线程进行通信

创建Message,并发送Message,处理Message

1. 创建Message

我们在Looper.loop()中知道,Message在发送后会被回收,那么我们一起看下Message的构造函数和回收函数

/** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
    */
public Message() {
}

private static final Object sPoolSync = new Object();
private static Message sPool;//单链表结构的头部引用
Message next;

public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;//复用Message
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    //sPool为null 则新建
    return new Message();
}

void recycleUnchecked() {
    //重置了Message的参数
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;
    
    synchronized (sPoolSync) {
        //将Message以单链表的方式存储
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            //sPool指向单链表的头部
            sPool = this;
            sPoolSize++;
        }
    }
}

由代码可以看出Message构造函数虽然是public的,但是官方建议我们用obtain()来或者Message。由obtain()和recycleUnchecked()代码可以看出Message采用一个单链表结构的对象池,来复用Message对象。

2. 消息发送handler.sendMessage和处理

看源码可知,handler.sendMessage的几个重载的方法,最终是调用了sendMessageAtTime方法,而sendMessageAtTime又调用了enqueueMessage方法,而enqueueMessage方法最终是调用了MessageQueue的enqueueMessage方法,把Message加入到了消息队列中

伪代码调用逻辑如下

handler.sendMessage(Message msg){
    sendMessageAtTime(Message msg, long uptimeMillis){
        enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis){
            MessageQueue.enqueueMessage(msg, uptimeMillis)
        }
    }
}

然后从Looper.loop()中可以看到,Message在被发送到MessageQueue中后,loop()中开启的死循环是调用了MessageQueue.next()方法取出了Message,并调用msg.target.dispatchMessage(msg)方法来分发msg,而msg.target就是handler,那么看下handler的dispatchMessage方法

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

public interface Callback {
    public boolean handleMessage(Message msg);
}

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

可以看出dispatchMessage有3中逻辑

  1. 调用了message.callback.run(),来处理message
    runOnUiThread(),handler.post(Runnable r)就是这样处理的
  2. handler的Callback接口方式来处理消息,在创建handler的时候可以指定一个mCallback来处理消息
  3. handler.handleMessage来最终处理消息

这样从消息循环的开启,到消息的发送,处理就完成了

总结

  1. Looper是和当前线程关联的,Looper.prepare()建立与调用它的当前线程的关联,Looper.loop()开启当前线程消息循环
  2. handler是和Looper关联的,创建handler的时候必须指定其Looper,而主线程由于在程序开启时就开启了它的消息循环,所以只有在主线程创建handler的时候,不需要指定其Looper
  3. 创建Message,用Message.obtain(),可以复用Message,不要直接new。
  4. 在子线程中开启的消息循环,可调用Looper.myLooper().quit(),来退出消息循环,主线程的消息循环不可退出

你可能感兴趣的:(消息循环机制及其原理)