这节介绍Handler类使用相关的知识(以下分析都是基于android 12代码)

1. Handler的使用

1.1 创建Handler实例

创建Handler实例直接调用相应的构造函数即可,如下:

    public Handler() {this(null, false);}public Handler(@Nullable Callback callback) {this(callback, false);}public Handler(@NonNull Looper looper) {this(looper, null, false);}public Handler(boolean async) {this(null, async);}public Handler(@Nullable 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();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread " + Thread.currentThread()+ " that has not called Looper.prepare()");}mQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;}public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {mLooper = looper;mQueue = looper.mQueue;mCallback = callback;mAsynchronous = async;}

Handler类提供了各种重载的构造方法,现介绍下它的几个属性:

  • mLooper:如果构造方法中传递的looper为null,则直接调用Looper.myLooper方法获取线程对应的Looper,不存在则抛异常
  • mQueue:l类型MessageQueue
  • mCallback:类型为Callback,设置了这个属性,在dispatchMessage方法中会先执行它的回调
  • mAsynchronous:若它的值为true,代表通过Handler创建的Message都是异步的

1.2 创建Message的方法

Handler提供了创建Message的方法,如下:

    public final Message obtainMessage(){return Message.obtain(this);}public final Message obtainMessage(int what){return Message.obtain(this, what);}

上面只贴了一部分,主要是为了更方便的创建Message,Handler提供了这些重载方法。

1.3 执行Runnable

Handler提供了执行Runnable的方法,如下:

    public final boolean post(@NonNull Runnable r) {return  sendMessageDelayed(getPostMessage(r), 0);}public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {return sendMessageAtTime(getPostMessage(r), uptimeMillis);}public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {return sendMessageDelayed(getPostMessage(r), delayMillis);}

如上面,Handler可以直接post一个Runnable,还可以delay一段时间后执行Runnable,还可以在某个时间点执行Runnable

1.4 延迟或者在某个时间点执行Message

    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {if (delayMillis < 0) {delayMillis = 0;}return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}public boolean sendMessageAtTime(@NonNull 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提供的功能,但是如果在使用的时候,如果使用不当有可能会出现内存泄漏的问题,那下面就来介绍下相关的内容

2. Handler使用不当与内存泄漏

内存泄漏
一个对象本应该在它“生命结束”后,被垃圾回收器回收掉。但是由于一个生命周期更长的对象引用了它,导致垃圾回收器无法完成回收。它作为一个“毫无用处”的对象,占用着“无辜”的内存。

造成内存泄漏原因分析

下面是一段Handler使用不当,有可能会造成内存泄漏的代码

    public class MyActivity extends Activity{private Handler handler = new Handler(){@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);if (msg.what == 1 ){}}}protected void onResume() {super.onResume();handler.postDelayed(new Runnable(){省略业务代码},10);    }}

上面的代码在Activity的onResume方法中,在10s后去执行一个Runnable,这段代码是比较容易出现内存泄漏的,但是并不是说一定会出现。

在这样的场景下会出现:Activity的onResume方法被执行后,这时候用户刚好要退出Activity,那这种场景下必出现内存泄漏。

来分析下为啥上面的场景会出现内存泄漏:

  • Handler handler的实例是一个匿名内部类,匿名内部类编译器会为它增加一个Activity类型的属性,同时它的构造函数增加一个参数,这个参数指向了当前的Activity对象,这样handler就持有了当前Activity对象。
  • new Runnable的时候也是一个匿名内部类,它同样也持有当前的Activity对象
  • 在调用handler.postDelayed这个方法的时候,最终会创建一个Message对象,这个Message的callback属性指向了上面创建的Runnable,同时它的target属性指向了handler。创建的Message对象会被放入MessageQueue的链表中,在10s后才能执行。
  • 因为当前Activity被用户销毁了变成“无用”对象了,但是MessageQueue的链表却还间接的引用着当前的Activity,MessageQueue的生命周期与app进程是一致的,最终导致当前的Activity对象不能被即时回收

解决内存泄漏
如下代码:

    public class MyActivity extends Activity{private Handler handler = new MyHandler(this);private static class MyHandler extends Handler{private WeakReference<Activity> activity;MyHandler(Activity activity) {this.activity = new WeakReference<>(activity);}}private Runnable runnable = new Runnable(){省略业务代码};protected void onResume() {super.onResume();handler.postDelayed(runnable,10);    }@Overrideprotected void onDestroy() {super.onDestroy();handler.removeCallbacks(runnable);}}

如上代码可以解决Handler使用不当,导致有可能出现内存泄漏问题:

  • 把Handler类的子类定义为静态内部类,使用弱引用来引用Activity对象
  • 在onDestory的方法中,调用handler的removeCallbacks方法,把runnable从MessageQueue的链表中移除掉

总结

到此关于Handler的介绍就结束了,关于handler机制系列的文章也介绍完了,欢迎关注其他系列文章。

handler机制--Handler使用相关推荐

  1. 【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )

    文章目录 I . Handler 机制简介 II . Handler 机制 Handler Message Looper MessageQueue 四组件对应关系 III . Handler ( 消息 ...

  2. 【Android 异步操作】Handler 机制 ( Handler 常用用法 | HandlerThread 简介 | HandlerThread 源码注释分析 )

    文章目录 一.Handler 常用用法 二.HandlerThread 简介 三.HandlerThread 源码 一.Handler 常用用法 主线程 Handler 主要作用 : Looper 和 ...

  3. handler机制--handler概览

    本节主要是对handler机制有一个大概的了解,后面的章节还会详细的分析handler机制. handler产生背景 在介绍handler之前先来介绍下它产生的背景,只有了解了背景才能加深对它的了解. ...

  4. Handler 机制分析

    android 子线程和UI线程的交互主要使用Handler的方法进行通信.本文分析Handler机制 Handler 如何使用? Handler的使用比较简单 public class MainAc ...

  5. Android面试——Handler 机制

    Android面试--Handler 机制 一.Handler机制 Handler机制围绕的三个点 1.Handler负责消息的发送和接受 发送给消息MessageQueue和接受Looper返回的消 ...

  6. Android消息机制Handler用法

    这篇文章介绍了Android消息机制Handler用法总结,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 1.简述 Handler消息机制主要包括: Messa ...

  7. android Handler机制之ThreadLocal详解

    概述 我们在谈Handler机制的时候,其实也就是谈Handler.Message.Looper.MessageQueue之间的关系,对于其工作原理我们不做详解(Handler机制详解). Messa ...

  8. Android多线程:深入分析 Handler机制源码(二)

    前言 在Android开发的多线程应用场景中,Handler机制十分常用 接下来,深入分析 Handler机制的源码,希望加深理解 目录 1. Handler 机制简介 定义 一套 Android 消 ...

  9. Android之异步消息处理机制Handler源码解析

    转载请标明出处: http://blog.csdn.net/hai_qing_xu_kong/article/details/76083113 本文出自:[顾林海的博客] 个人开发的微信小程序,目前功 ...

最新文章

  1. lintcode:删除链表中指定元素
  2. Edit Distance编辑距离(NM tag)- sam/bam格式解读进阶
  3. 计算机丢失wininet,win7系统启动程序提示因为计算机中丢失wininet.dll的解决方法...
  4. 学python找什么工作-学Python能找到什么工作?这4种工作最热门!
  5. 部署shiro官方源码时,执行maven命令出错
  6. 网络爬虫--9.正则表达式
  7. linux nohup后台执行管道操作
  8. Linux学习8-CentOS部署自己本地的django项目
  9. mapxtreme is still in evalutation!
  10. java9什么时候公布_Java 9正式版有可能被推迟到9月21号发布
  11. PCB设计中电源与地之间电容的作用(具体放置面积, 大小等等)
  12. YUM更换源(1)--yum找不到安装包
  13. 论文阅读笔记——Adversarial Attack on Attackers Post-Process to
  14. 报表系统服务器故障,报表服务器服务启动时的错误消息 - SQL Server | Microsoft Docs...
  15. 对java老师的评价及建议_对老师的评价及建议
  16. 这里带你了解IR2104驱动电路
  17. 其实我们可以做自己的心理医生
  18. 主板芯片组和内存映射
  19. 棒球比赛和训练来评估球员的潜力·棒球1号位
  20. Dubbo - Dubbo的SPI机制

热门文章

  1. Google.cn刚上不去了
  2. mactex学习笔记(1)
  3. jQuery操作复选框checkbox技巧总结 ---- 设置选中、取消选中、获取被选中的值、判断是否选中等
  4. Mac下brew的安装
  5. Android 源码之overlay分析
  6. 数据结构之数据、数据元素、数据项、数据对象之间的关系
  7. matlab 对矩阵进行复制 || repmat
  8. C语言中的空指针、空指针常量、NULL 0
  9. 超级实用(附技巧)——用word与谷歌翻译将英文PDF文档翻译成中文,免费无限制
  10. 聚类与分类方法的主要区别是什么?