Handler class should be static or leaks might occur
在Android线程通信中,常用的方法就是创建一个Message(android.os.Message) 对象,并将它的what字段指定对应值,调用Handler的sendMessage() 方法将这个Message发送出去。代码如下
val handler = object : Handler() {
val TEST = 1
override fun handleMessage(msg: Message) {
when (msg.what) {
TEST -> {
TODO()
}
}
}
}
大部分的教材都会使用这个方法,但是在编程中,我们会发现这样的代码会存在几个问题
-
Handler class should be static or leaks might occur
This Handler class should be static or leaks might occur (anonymous android.os.Handler)
这是因为Handler在Android中用于消息的发送与异步处理,常常在Activity中作为一个匿名内部类来定义,此时Handler会隐式地持有一个外部类对象(通常是一个Activity)的引用。当Activity已经被用户关闭时,由于Handler持有Activity的引用造成Activity无法被GC回收,这样容易造成内存泄露。
解决方法:将其定义成一个静态内部类(此时不会持有外部类对象的引用),在构造方法中传入Activity并对Activity对象增加一个弱引用,这样Activity被用户关闭之后,即便异步消息还未处理完毕,Activity也能够被GC回收,从而避免了内存泄露。
val handler = MyHandler(this)
class MyHandler(activity: Activity) : Handler() {
private var reference: WeakReference<Activity>? = null
init {
reference = WeakReference<Activity>(activity)
}
override fun handleMessage(msg: Message) {
if (reference?.get() == null) {
return
} else {
when (msg.what) {
0 -> {
TODO()
}
}
}
}
}
-
‘constructor Handler()’ is deprecated
'constructor Handler()' is deprecated. Deprecated in Java
我们进入到Handler.java文件中,会发现无参构造函数已经被deprecated了
@Deprecated
public Handler() {
this(null, false);
}
官方给出了存在的隐患
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
被弃用的理由
* @deprecated Implicitly choosing a Looper during Handler construction can lead to bugs
* where operations are silently lost (if the Handler is not expecting new tasks and quits),
* crashes (if a handler is sometimes created on a thread without a Looper active), or race
* conditions, where the thread a handler is associated with is not what the author
* anticipated. Instead, use an {@link java.util.concurrent.Executor} or specify the Looper
* explicitly, using {@link Looper#getMainLooper}, {link android.view.View#getHandler}, or
* similar. If the implicit thread local behavior is required for compatibility, use
* {@code new Handler(Looper.myLooper())} to make it clear to readers.
解决方法:
- 使用Handler(@NonNull Looper looper)
- 使用Handler(@NonNull Looper looper, @Nullable Callback callback)
val handler = Handler(Looper.getMainLooper())
val handler = Handler(Looper.getMainLooper(), object : Handler.Callback {
override fun handleMessage(msg: Message): Boolean {
TODO("Not yet implemented")
}
})
val handler = Handler(Looper.getMainLooper()
) { TODO("Not yet implemented") }
|