Java (可能)自定义ThreadPoolExecutor内存泄漏
为了在我的Android应用程序中集中后台线程处理,我定义了以下Java (可能)自定义ThreadPoolExecutor内存泄漏,java,android,kotlin,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() {
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
}
}
其思想是将此执行器用于所有后台任务
可以观察taskCount
对象,例如,根据当前是否有任务运行来显示/隐藏ProgressBar
taskCount
对象只能从主线程访问,因此不应该存在任何并发问题(如果我错了,请纠正我)
回调
是ThreadPoolExecutor
实例本身(它是一个单例),并且在任务完成后,引用将被清除,因此这也不应该是问题(再次,如果我错了,请纠正我)
问题:
要将数据插入数据库,我将调用我的活动(或片段)的以下方法
private fun saveTestData(测试项:列表){
customThreadPoolExecutor.executeTask(任务(可运行{
testService.saveAll(testItems)
}))
}
这里的Runnable
是一个匿名的内部类,因此(我认为)包含了对所包含的活动的引用
因此,Runnable
(以及包装任务
)无法进行垃圾收集,因此每次调用此方法时,实例计数都会增加(并且不会减少)
我的假设正确吗
如果是,我如何解决这个问题
(也欢迎Java回答)为什么要无限期地保留该实例?在它执行之后,第二件事就是,将ThreadPoolExecutor子类化是个坏主意。Kotlin为MarkoTopolnik提供了一流的功能。@MarkoTopolnik感谢您的回复。那么除了子类化之外,你认为这是一个可行的概念吗?或者你看到其他的缺陷了吗?如果这是我的项目,我会用协同程序来代替。我几乎不需要支持代码来实现它。非常简单的示例:this.launch{initialStuff();val result=withContext(MyThreadPool){networkOperation()};updateGui(result)}
。这里这应该是您的活动或实现CoroutineScope
的片段。如果活动被销毁,它会自动取消所有后台任务。
@Provides
@Singleton
fun provideCustomThreadPoolExecutor(): CustomThreadPoolExecutor = CustomThreadPoolExecutor()
private fun saveTestData(testItems: List<TestItem>) {
customThreadPoolExecutor.executeTask(Task(Runnable {
testService.saveAll(testItems)
}))
}