要在我的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
对象只能从主线程访问,因此不应该存在任何并发问题(如果我错了,请纠正我)。
callback
是ThreadPoolExecutor
实例本身(是一个单例),并且在任务完成后立即清除了引用,因此这也不应该成为问题(再次,请如果我错了请指正)。
问题:
要将数据插入数据库,请调用Activity
(或Fragment
)的以下方法
private fun saveTestData(testItems: List<TestItem>) {
customThreadPoolExecutor.executeTask(Task(Runnable {
testService.saveAll(testItems)
}))
}
这里的Runnable
是一个匿名内部类,因此(我认为)持有对封闭的Activity
(或Fragment
)的引用。
因此,Runnable
(和包装的Task
)无法被垃圾回收,因此每次我调用此方法时,实例数量都会增加(并且永远不会减少)。
我的假设正确吗?
如果是这样,我怎么解决这个问题?
(也欢迎Java回答)