Android开发中,咱们常常运用Android SDK提供的Handler类来完成线程间通讯的使命,可是项目代码中,常常看到Handler过于随意地运用,这些运用或许有一些危险,本文记录下这些问题,并给出相关主张。

问题一:运用默许无参结构来创立Handler

Handler有个无参结构办法,有的时分偷懒在Activity中直接经过无参结构办法来创立Handler目标,例如:

private final Handler mHandler = new Handler();

那么这个Handler目标会运用当时线程的Looper,这在Activity或自定义View中或许没问题,由于主线程是存在Looper的,可是在子线程中就会呈现异常,由于子线程很或许没有进行过Looper.prepare()。别的一个危险是,new Handler()运用“当时线程”的Looper,或许预期是在子线程,可是一开始的外部调用是在主线程,那么这个运用或许影响主线程的交互体验。

  • 主张:创立Handler目标时必须传递Looper参数来保证Looper的存在并显式操控其线程。

问题二:Looper.getMainLooper()的乱用

在Activity中咱们可以运用runOnUiThread办法把一个过程放在主线程执行,可是在其他地方,经过Looper.getMainLooper()也是一个简单的办法,例如:

new Handler(Looper.getMainLooper()).post(() -> {
    //do something ...
});

由于太方便了,所以到处都可以用,那么就存在了一个危险:任何线程都可以经过这种办法来影响主线程。有或许在装备较差的手机呈现意料之外的卡顿,并且这种卡顿或许有必定随机性,不简单复现,给排查问题的时分形成必定难度。

  • 主张:防止在线程外部创立该线程的Handler,例如,尽量防止在ActivityFragment和自定义View以外的地方创立主线程的Handler

问题三:在业务功能层面直接创立Hanlder

在开发中,有时分需要运用Handler来切换线程,或者运用Handler的音讯功能,然后直接运用Handler,例如下面这段代码:

new Thread(() -> {
    presenter.doTaskInBackground();
    new Handler(Looper.getMainLooper()).post(() -> {
        updateViewInMainThread();
    });
}).start()

这个代码槽点太多,这儿主要讲下关于Handler的。其实程序的成果并没有什么问题,不足之处在于把Handler这种平台相关的概念混到了业务功能代码里,就好像一个人在读诗朗诵,念完“两个黄鹂鸣翠柳”,然后下面冒出一句“我先喝口水”,喝完水然后继续念。

  • 主张:将Handler的创立和毁掉放到框架层面,甚至可以封装一套运用的接口,而不是直接运用postsend等办法。

问题四:没有及时移除Hanlder的音讯和回调

HandlerpostDelayedpostAtTime是两个便当的办法,可是这个办法并没有和组件的生命周期绑定,很简单形成Activity或其他大型目标无法及时释放。

  • 主张:不需要的时分,及时调用removeCallbacksAndMessages办法