一点Andorid开发小建议:妥善使用和管理Handler
在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
方法
链接:https://juejin.cn/post/7240467781401051192
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。