(可能)使用自定义ThreadPoolExecutor导致内存泄漏

时间:2018-10-17 09:03:40

标签: java android kotlin

要在我的Android应用中集中处理后台线程,我定义了以下Runnable

class Task(private val runnable: Runnable) : Runnable {

    interface Callback {
        fun onTaskStarted()
        fun onTaskFinished()
    }

    var callback: Callback? = null

    override fun run() {
        callback?.run { mainHandler.post { this.onTaskStarted() } }
        runnable.run()
        callback?.run { mainHandler.post { this.onTaskFinished() } }

        // setting callback to null, so the Task instance can be garbage collected
        callback = null
    }

    companion object {
        private val mainHandler = Handler(Looper.getMainLooper())
    }
}

以及以下ThreadPoolExecutor

class CustomThreadPoolExecutor :
        ThreadPoolExecutor(2, 2, 0L, TimeUnit.MILLISECONDS, LinkedBlockingQueue<Runnable>()),
        Task.Callback {

    val taskCount: MutableLiveData<Int> by lazy {
        MutableLiveData<Int>().apply { value = 0 }
    }

    fun executeTask(task: Task) {
        task.callback = this
        super.execute(task)
    }

    @MainThread
    override fun onTaskStarted() {
        taskCount.value = taskCount.value?.plus(1) ?: 1
    }

    @MainThread
    override fun onTaskFinished() {
        taskCount.value = taskCount.value?.minus(1) ?: 0
    }
}

后者是 Dagger 提供的单例:

@Provides
@Singleton
fun provideCustomThreadPoolExecutor(): CustomThreadPoolExecutor = CustomThreadPoolExecutor()

想法是使用此执行程序执行所有后台任务。

可以观察taskCount对象,例如根据当前是否正在运行任务来显示/隐藏ProgressBar

taskCount对象只能从主线程访问,因此不应该存在任何并发问题(如果我错了,请纠正我)。

callbackThreadPoolExecutor实例本身(是一个单例),并且在任务完成后立即清除了引用,因此这也不应该成为问题(再次,请如果我错了请指正)。

问题:

要将数据插入数据库,请调用Activity(或Fragment)的以下方法

private fun saveTestData(testItems: List<TestItem>) {
    customThreadPoolExecutor.executeTask(Task(Runnable {
        testService.saveAll(testItems)
    }))
}

这里的Runnable是一个匿名内部类,因此(我认为)持有对封闭的Activity(或Fragment)的引用。

因此,Runnable(和包装的Task)无法被垃圾回收,因此每次我调用此方法时,实例数量都会增加(并且永远不会减少)。

我的假设正确吗?

如果是这样,我怎么解决这个问题?

(也欢迎Java回答)

0 个答案:

没有答案