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

Android Handler机制源码浅析(上)

程序员文章站 2022-07-14 15:11:35
...

1.Handler.java

Android Handler机制源码浅析(下) :https://blog.csdn.net/XCF95319605/article/details/81088119

Handler的主要作用是消息的发送和接收(处理消息),handler内部是通过一系列的post方法和send方法来进行消息的发送,不过post方法都是通过间接调用send方法来完成的

Handler中的post方法列表

  • post(Runnable r)
  • postAtTime(Runnable r, long uptimeMillis)
  • postAtTime(Runnable r, Object token, long uptimeMillis)
  • postDelayed(Runnable r, long delayMillis)
  • postAtFrontOfQueue(Runnable r)

Handler中send方法列表

  • sendMessage(Message msg)
  • sendEmptyMessage(int what)
  • sendEmptyMessageDelayed(int what, long delayMillis)
  • sendEmptyMessageAtTime(int what, long uptimeMillis)
  • sendMessageDelayed(Message msg, long delayMillis)
  • sendMessageAtTime(Message msg, long uptimeMillis)
  • sendMessageAtFrontOfQueue(Message msg)
  • sendMonitorMessage(Message msg, long delayMillis, long executiontimeout, long pendingtimeout, String msgLoggerName)

(1) 随便找一个post方法和send方法来进行分析,我们先来看看post方法:

public final boolean post(Runnable r)
{
return  sendMessageDelayed(getPostMessage(r), 0);
}

在这里我们发现post方法被调用以后就直接调用了send方法中的sendMessageDelayed方法来进行消息的发送,其他post方法也是类似的,只是传入的参数和调用了不同的send方法而已,有兴趣可以去看源码。

接下来看一下sendMessageAtTime,因为sendMessage会间接调用到这个方法,所以就对这个方法进行分析:

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); //调用enqueueMessage方法
 }
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis); //将msg方法消息队列中
 }

其实我们平时是调用sendMessage方法,但是sendMessage会直接调用sendMessageDelayed方法,而sendMessageDelayed又会直接调用到sendMessageAtTime方法,所以就忽略掉前面部分,直接从sendMessageAtTime开始分析,首先sendMessageAtTime被调用时,会先获取到当前的MessageQueue,进行判空,然后调用enqueueMessage方法,enqueueMessage最后将消息插入到消息队列,至此完成了一次简单的Message的发送流程。

(2) 接下来我们来分析一下Handler处理消息的过程:

handler是通过dispatchMessage方法来处理消息的,而dispatchMessage方法是被在Looper中被调用的,我们首先来看一下dispatchMessage的源码实现,然后再去分析Looper中对dispatchMessage的调用,Handler中dispatchMessage源码实现:

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

dispatchMessage的源码很简单,第一步:先检查msg的callback(Runnable)是否为空,若不为空,则交给handlerCallback处理,我们来看看handlerCallback源码做了什么:

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

handlerCallback的源码也很简单,就是开启传进来的message的run方法,那么问题来了,为什么有run方法,相信从前面的post方法你已经看出来了,这个run方法就是前面通过post发送消息时传递进来的那个Runnable实现类的run方法,好了,第一个if语句已经剖析清楚了。

接下来我们看看第二个if语句,检查mCallback是否为空,不为空则将消息交给handlerMessage来处理,首先我们来看看mCallback在源码中的定义:

final Callback mCallback; //Callback类

我们再看看Callback的定义:

/**
 * Callback interface you can use when instantiating a Handler to avoid
 * having to implement your own subclass of Handler.
 *
 * @param msg A {@link android.os.Message Message} object
 * @return True if no further handling is desired
 */
public interface Callback {
    public boolean handleMessage(Message msg);
}

那么这个mCallback又是在哪初始化的呢?还是看源码:

public Handler(Callback callback) {
        this(callback, false);
 }
 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;
}

原来是当我们采用传入一个callback来获取一个handler实例的时候,重写里面的handleMessage来处理具体的消息,在Callback的接口的上面注释以及说明了:在实例化处理程序时可以使用的回调接口,以避免实现自己的Handler子类。

最后程序将会把消息交给我们重写的handleMessage来进行处理,至此,整个Handler的消息处理过程分析完毕。

2.Looper.java

Looper在Android消息机制中就专门负责循环的去监听消息,监听哪儿的消息呢?对就是MessageQueue里面的消息,当MessageQueue里面有消息的时候Looper就会去将消息取出来给Handler进行处理,首先我们来分析一下Looper 的构造方法:

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
 }

很简单,构造方法就做了两件事,首先是创建一个消息队列,然后将当前Looper所在的线程进行了保存操作。

Handler正常工作是离不开Looper的,那么为什么我们平时在UI线程使用Handler的时候却没有手动的去创建Looper呢?那是因为Android系统默认帮我们在主线程创建了一个Looper所以并不需要我们去手动的创建Looper对象,以下源码是在ActivityThread中的main方法中,Android系统为我们创建Looper的过程,已经删减掉和Looper无关的代码:

public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        ...
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
 }

接下来我们来分析一下UI线程获取到Looper的过程,在main方法中首先调用了Looper的prepareMainLooper()方法,该方法是用来实例化Looper对象的,跟着源码的调用轨迹来看一下调用过程:

public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
          throw new IllegalStateException("The main Looper has already been prepared.");
        }
           sMainLooper = myLooper();//调用myLooper()获取Looper对象
    }
 }

 返回与当前线程相关联的Looper对象,如果调用线程没有与Looper关联,则返回null。

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

最后调用Looper.loop();来开启Looper循环,接下来我们来分析一下loop方法的实现:

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
       throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
final MessageQueue queue = me.mQueue;
    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
       final Printer logging = me.mLogging;
       if (logging != null) {
           logging.println(">>>>> Dispatching to " + msg.target + " " +
                   msg.callback + ": " + msg.what);
       }

       final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
       final long traceTag = me.mTraceTag;
       if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
           Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
       }
       final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
       final long end;
       try {
           msg.target.dispatchMessage(msg);
           end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
       } finally {
           if (traceTag != 0) {
               Trace.traceEnd(traceTag);
           }
       }
       if (slowDispatchThresholdMs > 0) {
           final long time = end - start;
           if (time > slowDispatchThresholdMs) {
               Slog.w(TAG, "Dispatch took " + time + "ms on "
                       + Thread.currentThread().getName() + ", h=" +
                       msg.target + " cb=" + msg.callback + " msg=" + msg.what);
           }
       }

       if (logging != null) {
           logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
       }

       // 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);
       }

       msg.recycleUnchecked();
   }
}

loop方法里面最重要的地方就是for(;;)代码块,里面是一个死循环,而跳出该循环的唯一条件是msg为空,就是当MessageQueue的next方法返回了null。如果next方法返回了新的消息,looper就会处理这条消息:msg.target.dispatchMessage(msg);,这里的msg.target指的是发送这条消息的对象,这样,相当于消息最后又回到了Handler本身去处理消息。至此整个Looper的工作流程就基本分析完毕了,就是通过Looper的构造器创建一个消息队列,然后通过prepareMainLooper在当前线程实例化Looper对象,最后通过loop方法来开启循环,处理相应的消息,只是所谓的处理是把消息对象返回给发送这条消息的Handler对象。

Looper除了提供prepareMainLooper让UI线程实例化Looper以外,还提供了prepare()方法来方便我们在任意线程实例化Looper对象,使用方式可参考上面main方法中,都是先通过prepare()来实例化对象,然后通过loop()方法来开启循环。

至此,整个Looper的循环处理过程就分析完毕了。

Android Handler机制源码浅析(下) :https://blog.csdn.net/XCF95319605/article/details/81088119