欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Handler、Looper源码学习

程序员文章站 2022-07-14 16:46:16
...

Android中,使用Handler,Looper的场景主要是跨线程通信,先看一个简单的例子:

public class MainActivity extends Activity {
    public final static int MESSAGE_TYPE_1 = 1;

    private WorkHandler mHandler;
    private static class WorkHandler extends Handler {
        public WorkHandler(Looper looper) {
            super(looper);
        }

        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MESSAGE_TYPE_1:
                    LogUtils.d("this is message 1");
                    // do something...
                    break;
                default:
                    break;
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        HandlerThread thread = new HandlerThread("work_thread"); // 创建一个线程对象
        thread.start(); // 启动子线程,这时会利用HandlerThread#run方法,创建一个Looper对象,绑定子线程,线程的执行并进入loop循环模式
        mHandler = new WorkHandler(thread.getLooper()); // 创建一个Handler对象,并传入Looper

        Message msg = new Message();
        msg.what = MESSAGE_TYPE_1;
        mHandler.sendMessage(msg); // 通过主线程发送1个消息,消息被压入messageQueue(所属于Looper对象)
    }
}

这里涉及到4个重要的类:Handler,Looper,MessageQueue(Handler和Looper的成员变量),HandlerThread。

1. Handler
public class Handler {
      final Looper mLooper; 
      final MessageQueue mQueue;

      public Handler(Looper looper, Callback callback, boolean async) {
           mLooper = looper;
           mQueue = looper.mQueue;
           // ...
     }
}

Handler类有2个成员变量,mLooper和mQueue,从构造函数可看出,mQueue用的也是Looper的成员变量。所以本质上Handler含有1个Looper对象。
Handler有2个重要的方法,我们经常用到,sendMessage和handleMessage。

  • sendMessage的真正实现是enqueueMessage方法,如下:
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
          msg.target = this;  // 重要步骤1. 将此Handler对象绑定到此Message对象,以便将来Looper.loop方法中调用目标Handler对象来处理此消息
          if (mAsynchronous) {
              msg.setAsynchronous(true);
          }
          return queue.enqueueMessage(msg, uptimeMillis);
      }
    
    将一条新消息Message压入MessageQueue对象(即mQueue,所属于mLooper),默认是同步,Handler初始化时可设置消息发送是否异步
  • handleMessage是处理消息的函数,由dispatchMessage方法所调用,一般应用使用时重写handleMessage函数,定制自己的消息处理逻辑

2. Looper

Looper类有2个重要的成员变量,mQueue和mThread,另外还有1个所属于进程的sThreadLocal集合,ThreadLocal<Looper>本质是一个Map数据结构,key是线程对象,value是Looper对象。它的作用是保存进程中所有<Thread,Looper>的信息,保证Looper对象和线程1:1对应。

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

    final MessageQueue mQueue;
    final Thread mThread;
    // ...
}

Looper有3个重要的静态方法:prepare,prepareMainLooper,loop。

  • prepare方法是为本线程创建一个Looper对象,并插入sThreadLocal中保存
private static void prepare(boolean quitAllowed) {
     if (sThreadLocal.get() != null) {
         throw new RuntimeException("Only one Looper may be created per thLooper.prepare,Looper.loop等read");
     }
     sThreadLocal.set(new Looper(quitAllowed));
}
  • prepareMainLooper方法是给ActivityThread#main方法调用的,进程启动时最先执行的入口函数里,完成主线程Looper的初始化。因为时机是最早的,如果应用在启动完成后,再调用此方法,会抛出异常
public static void prepareMainLooper() {
      prepare(false); // false代表参数quitAllowed的值,表示不允许退出
      synchronized (Looper.class) {
          if (sMainLooper != null) {
              throw new IllegalStateException("The main Looper has already been prepared.");
          }
          sMainLooper = myLooper();
      }
}
  • loop方法的核心是一个无限循环,不断从mQueue中取出新消息,调用目标Handler#dispatchMessage方法来处理消息,其中dispatchMessage里就会调用Handler#handleMessage方法
    public static void loop() {
        // ...
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            // ...
            msg.target.dispatchMessage(msg);
            // ...
        }
    }


3. MessageQueue

MessageQueue的实现较为复杂,主要是利用JNI,调用native相关方法,例如MessageQueue初始化时,调用nativeInit();
代码路径:frameworks/base/core/jni/android_os_MessageQueue.cpp
这里暂时先不深入研究,后面再补充。


4. HandlerThread

HandlerThread的实现很简单,继承于Thread类。作用是封装一个默认带Looper的Thread类,省去开发者自己调用Looper.prepare,Looper.loop等方法,使Handler的使用更方便。如本文开始的例子。
HandlerThread的核心方法是重写的run方法,其中会调用Looper.prepare,Looper.loop等。


总结:

  • 1条消息的生命周期总结如下,简单分为3步:
    handler.sendMessage(msg) --线程A发送消息,消息压入messageQueue----> looper.loop --线程B从messageQueue中取出消息----> handler.handleMessage(msg)--线程B消费掉此消息----> 结束
  • Handler,Looper,MessageQueue,从对象角度所属的关系:
    handler <----- looper <----- messageQueue
  • Looper#quit和Looper#quitSafely方法有何区别?
    a. Looper#quit -> mQueue#quit(false) -> mQueue#removeAllMessagesLocked
    直接终止Looper,不再处理所有消息
    b. Looper#quitSafely -> mQueue#quit(true) -> mQueue#removeAllFutureMessagesLocked
    处理完MessageQueue中已有消息,再终止Looper


    作者:kevin song,2018.11.20于南京建邺区