了解Handler源码

Handler 异步消息处理机制

  • 我们先来看一下一个标准的异步消息处理机制是如何写的.
class LooperThread extends Thread {  
              public Handler mHandler;  

              public void run() {  
                  Looper.prepare();  

                  mHandler = new Handler() {  
                      public void handleMessage(Message msg) {  
                          // process incoming messages here  
                      }  
                  };  

                  Looper.loop();  
              }  
          }  

以上代码摘自官方文档.

根据代码分析

Looper

  • 在创建Handler之前,必须先调用Looper.prepare()方法, 等等, 我们在UI线程使用Handler的时候并没有调用过这个方法啊! 是的, 这是因为在UI线程中已经调用了Looper.prepare()和Looper.loop()方法.
  • 现在一步一步来看看Looper中的prepare方法到底做了什么.
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));//创建了一个Looper对象
    }
  • 再看看Looper的构造方法:
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed); //创建了一个消息队列
        mThread = Thread.currentThread();
    }
  • 可以看到, 主要是调用了sThreadLocal.set()方法, 创建了一个Looper对象, 这里简单介绍一下ThreadLoacl是个什么东西,这里不作深入讨论:

    1. 是一个线程内部的数据存储类.
    2. 通过它可以在指定的线程中存储数据, 并且只有在该指定线程中获取到存储的数据.
    3. 对其他线程来说则无法获取到数据.
  • 通过以上代码我们知道:
    因为Looper.prepare只能调用一次, 所以一个线程只维护一个Looper对象和一个MessageQueue消息队列. 在这写准备好之后, 我们来看一下上面标准代码中的下一行, 创建Handler对象.

Handler

  • 还是从构造方法看起:
public Handler() {  
        this(null, false);  
}  
public Handler(Callback callback, boolean async) {  
        if (FIND_POTENTIAL_LEAKS) {  
            final Class<? extends Handler> 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());  
            }  
        }  

        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;  //获取这个Looper对象中保存的MessageQueue
        mCallback = callback;  
        mAsynchronous = async;  
    }  
  • 我们来看一下myLooper的方法:
public static @Nullable Looper myLooper() {
        return sThreadLocal.get(); //从当前线程获取保存的Looper对象
    }
  • 通过以上代码我们知道了handler的对象与我们Looper对象中MessageQueue是如何关联上的.
  • Looper对象有了, MessageQueue有了, Handler也有了, 我们先来回顾一下Handler是如何发送消息的:
new Thread(new Runnable() {  
    @Override  
    public void run() {  
        Message message = new Message(); //创建一条消息  
        message.arg1 = 1;  
        Bundle bundle = new Bundle();  
        bundle.putString("data", "data");  //bundle封装消息
        message.setData(bundle);  //消息保存数据
        handler.sendMessage(message);  //定义在主线程的Handler在子线程发送消息
    }  
}).start();  
  • 好, 我们先来看一下sendMessage到底做了什么.
public final boolean sendMessage(Message msg)  
 {  
     return sendMessageDelayed(msg, 0);  
 } 
public final boolean sendMessageDelayed(Message msg, long delayMillis)  
   {  
       if (delayMillis < 0) {  
           delayMillis = 0;  
       }  
       return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
   }  
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);  //这个方法毫无疑问就是入队的方法
   }  
  • Handler中提供了很多个发送消息的方法,我们在发送消息的时候除了sendMessageAtFrontOfQueue()方法之外,其它的发送消息方法最终都会辗转调用到sendMessageAtTime()方法中, 这个方法最终会调用Handler的enqueueMessage方法.
  • 我们再来看看enqueueMessage做了哪些事:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  
       msg.target = this;  //把当前的handler赋值为msg的target属性
       if (mAsynchronous) {  
           msg.setAsynchronous(true);  
       }  
       return queue.enqueueMessage(msg, uptimeMillis);  
   }  
  • enqueueMessage最终会调用queue的enqueueMessage的方法,也就是说handler发出的消息,最终会保存到消息队列中去。
  • 既然有入队, 肯定就有出队, 我们最后来看一下一开始的标准代码的最后一句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;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) { //让当前线程进入一个无限循环
            Message msg = queue.next(); // might block 不断从MessageQueue的对象中读取消息,即出队
            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
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);//每当有一个消息出队,就将它传递到该方法,msg.target即是前面赋值的Handler对象

            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();
        }
    }
  • 看完上面的注释, 我们来看看Handler的dispatchMessage做了什么:
 public void handleMessage(Message msg) {
    }

    /**
     * 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); //是不是很熟悉! 我们重写的handleMessage是在这里回调的!
     }
 }

最后

  • 总结一下:
    1. Looper主要的作用是通过loop()方法建立一个无限循环体, 在不断的从MessageQueue中去取消息,交给消息的target属性(即Handler对象)的dispatchMessage去回调handleMessage方法.
    2. Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
    3. Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
  • 感谢郭神和鸿洋的详细讲解, 本文很多内容就是来源于他们的博客, 最后贴张图,来自鸿洋大神:Android 异步消息处理机制
    这里写图片描述
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值