Android Handler机制源码浅析(上)

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值