Handler

来源:互联网 发布:迪联软件 编辑:程序博客网 时间:2024/06/07 04:58

问题:

  • Handler是什么?作用是什么?
  • Handler、Loop、MessageQueue、Thread各自的作用,和他们之间的关系。
  • 多个Handler实例发送消息时,为什么是当前Handler收到,而不是其他Handler收到
  • Looper.loop()为什么不阻塞主线程
  • 绘制、点击、Activit生命周期和Handler的关系
  • Handler.post()、Handler.handleMessage分别执行在什么线程
  • Message是如何发送的。
  • Handler导致如何Activity泄漏
  • HandlerThread 有什么作用## handler是什么? 作用是什么?我们讲Handler、Loop、MessageQueue等类的时候,最需要思考的一个问题是这些类是什么,作用是什么?

是什么?
个人理解,Handler系列类可以看成是简单的Java类,遵循java的运行时标准。
Handler可以认为是生产者、消费者模式中的生产者。Loop为消费者。MessageQueue是产品库存。
当这一套机制运用到android的GUI中时,就代表了我们所熟知的应用的主线程。当然,这一套机制也可以用于需要循环处理消息的地方。可以在源码中搜索Looper.prepare()方法,可发现android系统中还有97处使用这种方式来进行消息的生产与消费。

屏幕快照 2017-04-16 下午10.36.07

作用?
发送消息。
网上有说可以用于线程运行,个人觉得这个描述不准确,可以由如下源码得知,发送的Runnable也是被封装为消息由Looper消费掉的。

Handler.java

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

重点看下getPostMessage()方法

private static Message getPostMessage(Runnable r) {   Message m = Message.obtain();   m.callback = r;   return m;}

接着看下消费Message的地方:Looper.loop()放方法。

public static void loop() {    //删除了许多不是主要逻辑的代码   for (;;) {       Message msg = queue.next(); // might block       msg.target.dispatchMessage(msg);       msg.recycleUnchecked();   }}

Message 的消费又被传递给生成Message的Handler.dispatchMessage()方法。

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

Handler、Loop、MessageQueue、Thread各自的作用,和他们之间的关系。

由上面的代码分析,克制:从整个调用链来看,发送一个消息可以总结为:Handler发送消息,消息被存储到MessageQueue中,由Looper.loop()方法循环查询MessageQueue的队列,获取消息,并把消息分发给Handler自己处理。

职责划分:
Handler:发送消息,处理消息。
MessageQueue:缓存消息,并对消息按照时间轴排序
Looper:分发消息。Looper是一个死循环,需要在某个线程中调用,来完成常驻功能。

可以看下三者的关系图(图片来自经典随机Crash之二:Android消息机制
):

多个Handler实例发送消息时,为什么是当前Handler收到,而不是其他Handler收到

回答这个问题很好解决,只需要进入Hnadler类,的任意一个send*方法,一直往下跟,会发现,追踪都会调用到enqueueMessage()方法。会看到Message会把this赋值给Message.target。this就是Handler对象自己。如下:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis{   msg.target = this;   if (mAsynchronous) {       msg.setAsynchronous(true);   }   return queue.enqueueMessage(msg, uptimeMillis);}

在来看Looper.loop()方法,会调用Message.target.dispatchMessage()方法,并把Message当做参数传递。

public static void loop() {    //删除了许多不是主要逻辑的代码   for (;;) {       Message msg = queue.next(); // might block       msg.target.dispatchMessage(msg);       msg.recycleUnchecked();   }}

所以Handler发送消息时,百分百肯定是自己收到。

Looper.loop()为什么不阻塞主线程

我们把Looper作为一个普通的java类的方法来看到时,Looper.loop()方法会阻塞任何调用这个方法的方法所运行的线程。若在主线程中调用肯定也会阻塞掉主线程。

绘制、点击、Activit生命周期和Handler的关系

做过android的都知道,绘制、点击、activity生命周期都是在主线程中完成。即在ACtivityThread.java的Main方法调用的那个Looper中完成。
要说清楚这个问题,需要大幅的篇幅来说明,这里就不在做详细的描述。

与Handler的关系就是在穿件Handler时,使用的Looper为getMainLooper()获取的Looper。

主线程的Handler创建流程:

public static void main(String[] args) {    //现在Main线程中穿件一个looper。   Looper.prepareMainLooper();    //由于ThreadLocal.java使用的原理,创建的的Handler使用Looper及时Main线程的Looper。   ActivityThread thread = new ActivityThread();   thread.attach(false);   if (sMainThreadHandler == null) {       sMainThreadHandler = thread.getHandler();   }   Looper.loop();   throw new RuntimeException("Main thread loop unexpectedly exited");}

可以看到,使用的Handler是ActivityThread内部的一个Handler

Handler.post()、Handler.handleMessage分别执行在什么线程

  • Handler.post()执行在什么线程?
    这是个伪命题。java方法当然执行在调用他的线程。

  • Handler.handleMessage执行在什么线程。

    public static void loop() {
    //删除了许多不是主要逻辑的代码
    for (;;) {
    Message msg = queue.next(); // might block
    msg.target.dispatchMessage(msg);
    msg.recycleUnchecked();
    }
    }

    通过loop方法可以看出,Handler.handleMessage会在Looper.loop()方法中调用。
    所以是执行在调用Looper.prepare()方法的线程。
    所以主线程中new 的Handler,执行在主线程。

Message是如何发送的。

如下图(经典随机Crash之二:Android消息机制):

Handler导致如何Activity泄漏

View.postDelayed(new Runnable() {      @Override      public void run() {        //延迟执行的方法      }  }, time);

当使用Handler.postDelayed()方法时,Message会延迟一个time再执行。使用内部类的Runable会持有当前Activity的对象。当Activity.onDestory()方法执行后,Activity应该被销毁,但此时Activity还被Runable内部内持有,就会导致内存泄漏。

注意:
当此时Activity销毁时,time时间到,调用Activity中的某些方法,会导致crash。 详细可参看:经典随机Crash之二:Android消息机制

HandlerThread 有什么作用

HandlerThread 作用只需要看run()方法就够了。
可以看到调用HandlerThread.start()方法后,就会执行run()方法。此时就会进入Loop的死循环。完成有Looper.loop()方法完成消息的分发、执行

public void run() {   mTid = Process.myTid();   Looper.prepare();   synchronized (this) {       mLooper = Looper.myLooper();       notifyAll();   }   Process.setThreadPriority(mPriority);   onLooperPrepared();   Looper.loop();   mTid = -1;}

参考

安卓基础:Handler
ThreadLocal 类说明
经典随机Crash之二:Android消息机制

0 0
原创粉丝点击