在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
,例如,尽量防止在Activity
、Fragment
和自定义View以外的地方创立主线程的Handler
。
问题三:在业务功能层面直接创立Hanlder
在开发中,有时分需要运用Handler
来切换线程,或者运用Handler
的音讯功能,然后直接运用Handler
,例如下面这段代码:
new Thread(() -> {
presenter.doTaskInBackground();
new Handler(Looper.getMainLooper()).post(() -> {
updateViewInMainThread();
});
}).start()
这个代码槽点太多,这儿主要讲下关于Handler
的。其实程序的成果并没有什么问题,不足之处在于把Handler
这种平台相关的概念混到了业务功能代码里,就好像一个人在读诗朗诵,念完“两个黄鹂鸣翠柳”,然后下面冒出一句“我先喝口水”,喝完水然后继续念。
-
主张:将
Handler
的创立和毁掉放到框架层面,甚至可以封装一套运用的接口,而不是直接运用post
和send
等办法。
问题四:没有及时移除Hanlder的音讯和回调
Handler
的postDelayed
和postAtTime
是两个便当的办法,可是这个办法并没有和组件的生命周期绑定,很简单形成Activity
或其他大型目标无法及时释放。
-
主张:不需要的时分,及时调用
removeCallbacksAndMessages
办法