【Android源码】Handler 机制源码分析

161 阅读5分钟

为什么要使用Handler

  1. 因为在Android中访问UI只能在主线程中进行,如果在子线程中运行,则程序会抛出异常。

    // ViewRootImpl.java
    void checkThread() {
       if (mThread != Thread.currentThread()) {
           throw new CalledFromWrongThreadException(
                   "Only the original thread that created a view hierarchy can touch its views.");
       }
    }
    
  2. 为什么不允许在子线程中访问UI?

    因为Android的UI并不是线程安全的,如果在多线程中执行UI的操作,那么UI的状态是不可控的,这个时候就会出现各种问题。 那么最好的办法就是只能在一个线程中执行UI的操作。 而Android主线程中又不能执行耗时操作,因为那样就会导致程序的ANR。 所以Android提供了Handler这样的机制,用来在子线程中执行耗时操作之后,发送消息给主线程,主线程再执行UI的更新操作。

Handler机制原理分析

这里我们以Android UI线程的Handler来分析。

Handler的创建

Android的应用入口是ActivityThread.main()函数,UI线程的Handler就是在这个函数中创建的。

public static void main(String[] args) {
    Looper.prepareMainLooper();
    thread.attach(false);
    ActivityThread thread = new ActivityThread();
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    Looper.loop();
}

当main函数执行之后,应用就启动了,从这个时候开始,Looper就会一直从消息队列中取出消息并处理。而应用会通过Handler来不断的添加消息给消息队列。通过不断的添加消息和取出消息,整个消息机制就被运转起来了。

Looper

从上面可以看到在Handler创建前后,通过Looper的prepareloop方法,创建了Looper对象和开启消息循环。

  1. 构造函数

    private Looper(boolean quitAllowed) {
       mQueue = new MessageQueue(quitAllowed);
       mThread = Thread.currentThread();
    }
    
    1. 创建了MessageQueue对象,这个对象是消息队列,主要用来存放我们的消息,会在下面具体分析。
    2. 获取当前的线程并保存起来
  2. prepare

    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));
    }
    
    1. 判断ThreadLocal中在当前线程是否已经存在了Looper对象,如果存在,则抛出异常,所以可以得出在同一个线程中只能存在一个Looper对象。
    2. 在ThreadLocal存入当前线程的Looper对象。
    3. ThreadLocal对象是一个线程内部的数据存储类,通过它可以在指定的线程存储数据,当存储数据之后,就只能在指定的线程中获取到存储的数据,其他线程是不能获取到数据的。
  3. loop

    public static void loop() {
       final Looper me = myLooper();
       // 获取消息队列
       final MessageQueue queue = me.mQueue;
        // 死循环来轮询的从消息队列中获取消息
       for (;;) {
           Message msg = queue.next(); // might block
           if (msg == null) {
               return;
           }
           
           try {
               msg.target.dispatchMessage(msg);
           } finally {
               if (traceTag != 0) {
                   Trace.traceEnd(traceTag);
               }
           }
    
           msg.recycleUnchecked();
       }
    }
    
    1. loop函数会不断的从消息队列中取出消息,当queue.next()为空的时候就直接阻塞住
    2. msg不为空,调用msg.target.dispatchMessage(msg)处理消息,而msg.target其实就是Handler对象,取出消息之后就交给Handler来处理发送的消息了。
  4. quit

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

    调用MessageQueue的quit方法来退出Looper。其中上面的是直接退出,下面的是安全的退出,也就是只标记一下,当消息队列中的消息全部执行完成之后安全的退出。

    当我们在子线程中创建Looper和Handler的时候,如果我们不调用quit方法的话,子线程就会一直处于等待状态,所以我们需要调用quit方法退出Looper。

MessageQueue

在Looper中大量的使用到了MessageQueue,而MessageQueue主要就是两个操作插入消息和读取消息并删除消息,我们来一起分析下:

  1. 构造函数

    MessageQueue(boolean quitAllowed) {
       mQuitAllowed = quitAllowed;
       mPtr = nativeInit();
    }
    

    在构造函数中,调用了nativeInit方法在Native层创建了NativeMessageQueue和Looper,并将Looper设置给当前的线程。这个时候Java层和Native层都有了MessageQueue和Looper。 在Native层的Looper中,创建了一个管道,本质上就是一个文件,一个管道中有读和写两个文件操作符,通过读和写来将消息写入和读取。

  2. enqueueMessage 插入消息

    boolean enqueueMessage(Message msg, long when) {
        synchronized (this) {
           msg.markInUse();
           msg.when = when;
           Message p = mMessages;
           boolean needWake;
           if (p == null || when == 0 || when < p.when) {
               // New head, wake up the event queue if blocked.
               msg.next = p;
               mMessages = msg;
               needWake = mBlocked;
           } else {
               needWake = mBlocked && p.target == null && msg.isAsynchronous();
               Message prev;
               for (;;) {
                   prev = p;
                   p = p.next;
                   if (p == null || when < p.when) {
                       break;
                   }
                   if (needWake && p.isAsynchronous()) {
                       needWake = false;
                   }
               }
               msg.next = p; // invariant: p == prev.next
               prev.next = msg;
           }
    
           // We can assume mPtr != 0 because mQuitting is false.
           if (needWake) {
               nativeWake(mPtr);
           }
       }
       return true;
    }
    

    enqueueMessage其实就是构建好msg,并插入到单链表中。

  3. next 读取消息并删除消息

    Message next() {
        for (;;) {
            nativePollOnce(ptr, nextPollTimeoutMillis);
        }
    }
    

    next方法是一个无限循环方法,当消息队列中没有消息的时候,next方法会被阻塞在这里,当有新的消息的时候,next方法会最终返回这条消息并从单链表中移除。

Handler

  1. 构造函数

    public Handler(Callback callback, boolean async) {
    
       mLooper = Looper.myLooper();
       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;
    }
    
    1. 首先获取Looper对象,如果Looper对象为空,则抛出异常,所以当我们在子线程中创建Handler的时候,首先要通过Looper.prepare()来创建子线程的Looper对象。
    2. 通过Looper获取到MessageQueue
  2. 发送消息

    Handler的发送消息主要是post的方法和send的方法,而他们最终调用的都是:

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
       MessageQueue queue = mQueue;
       if (queue == null) {
           RuntimeException e = new RuntimeException(
                   this + " sendMessageAtTime() called with no mQueue");
           Log.w("Looper", e.getMessage(), e);
           return false;
       }
       return enqueueMessage(queue, msg, uptimeMillis);
    }
    
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
    

    Handler主要就是向消息队列中插入了一条消息,这个时候MessageQueue就会调用插入的方法来插入消息。

  3. 读取消息

    当Handler发送消息之后,MessageQueue就会通过next方法读取出这个消息,那么Looper的loop就不会被阻塞住,取出消息之后就调用了msg.target.dispatchMessage(msg)方法,最终交给Handler的dispatchMessage来执行。

    /**
    * Handle system messages here.
    */
    public void dispatchMessage(Message msg) {
       if (msg.callback != null) {
           handleCallback(msg);
       } else {
           if (mCallback != null) {
               if (mCallback.handleMessage(msg)) {
                   return;
               }
           }
           handleMessage(msg);
       }
    }
    
    1. 检查Message的callback是否为空,不为空则通过handleCallback来处理,而callback就是通过post传递过来的Runnable对象。直接调用run方法执行。

      private static void handleCallback(Message message) {
          message.callback.run();
      }
      
    2. 检查mCallback是否为空,不为空则调用mCallback.handleMessage方法处理消息。而mCallback就是我们在创建Handler的时候传递过去的callback。

      public interface Callback {
          public boolean handleMessage(Message msg);
      }
      public Handler(Callback callback) {
          this(callback, false);
      }
      
    3. 调用handleMessage(msg)处理消息。