注册

一点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,例如,尽量避免在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方法

作者:乐征skyline
链接:https://juejin.cn/post/7240467781401051192
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册