一、问题说明
class MyActivity : Activity() {
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
// startCheckClipboard 中存在耗时操作
CommandManager.startCheckClipboard { showCommandOtherTypeDialog() }
}
}
open fun showCommandOtherTypeDialog(){
CommandManager.showFormulaDialog(supportFragmentManager,true, MtCommandManager.CommandTypeEnum.COMMAND_TYPE_OTHER)
}
}
object CommandManager : CoroutineScope by WorkScope {
fun startCheckClipboard(block: (() -> Unit)? = null) {
// 耗时任务
...
block.get()?.invoke()
}
}
问题原因:startCheckClipboard 方法有耗时任务,造成了内存泄露。
二、解决方案
class MyActivity : Activity() {
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
// startCheckClipboard 中存在耗时操作
CommandManager.startCheckClipboard { showCommandOtherTypeDialog() }
}
}
open fun showCommandOtherTypeDialog(){
CommandManager.showFormulaDialog(supportFragmentManager,true, MtCommandManager.CommandTypeEnum.COMMAND_TYPE_OTHER)
}
}
object CommandManager : CoroutineScope by WorkScope {
fun startCheckClipboard(block: (() -> Unit)? = null) {
// 防止耗时任务造成内存泄露
val weakBlock: WeakReference<(() -> Unit)?> = WeakReference(block)
...
weakBlock.get()?.invoke()
}
}
我尝试在做耗时任务的过程中手动执行一次 GC,发现回调就不会执行了,说明这个方案不可行!
为什么会被回收掉呢?
很明显,lambda 方法内的新生代变量,很容易被回收的,如果让 lambda 的生命周期同 Activity 一致就可以了。
我们稍加改动:
class MyActivity : Activity() {
// 成员变量存储回调,方便耗时任务用弱引用存储 block,避免无法释放造成内存泄露
private val checkClipboardCallback = { showCommandOtherTypeDialog() }
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
// startCheckClipboard 中存在耗时操作
CommandManager.startCheckClipboard(checkClipboardCallback)
}
}
open fun showCommandOtherTypeDialog(){
CommandManager.showFormulaDialog(supportFragmentManager,true, MtCommandManager.CommandTypeEnum.COMMAND_TYPE_OTHER)
}
}
object CommandManager : CoroutineScope by WorkScope {
fun startCheckClipboard(block: (() -> Unit)? = null) {
// 防止耗时任务造成内存泄露
val weakBlock: WeakReference<(() -> Unit)?> = WeakReference(block)
...
weakBlock.get()?.invoke()
}
}
搞定!
|