我试图在ViewModel
中获取LiveData
更新,并确保观察器没有泄漏,但它确实泄漏了,典型的问题是观察器没有存储在变量中,但这里不是这样; λ被存储在变量中。
private val observer: (List<MusicFile>) -> Unit =
{ musicFiles: List<MusicFile> ->
_uiState.postValue(FragmentMusicListState(musicFiles))
}
init {
musicRepository.musicFiles.observeForever(observer)
}
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
public override fun onCleared() {
super.onCleared()
musicRepository.musicFiles.removeObserver(observer)
}
问题是在调用onCleared之后,观察者仍然是附加的,我用下面的测试验证了这一点。
@Test
fun onCleared_RemovesObserver() {
val musicRepository = MusicRepository.getInstance()
val context = InstrumentationRegistry.getInstrumentation().targetContext
musicRepository.loadMusicFiles(context.contentResolver)
val musicFiles = musicRepository.musicFiles
val viewModel = FragmentMusicListViewModel(SavedStateHandle(), musicRepository)
viewModel.onCleared()
assert(!musicFiles.hasObservers())
}
另外,我已经调试了最后一行的测试,musicFile的属性显示观察者仍然是附着的,mActiveCount和mObservers属性显示观察者仍然是附着的。
我实际上如何删除观察者?
1条答案
按热度按时间mspsb9vt1#
LiveData在observeForever和removeObserver中接受一个
Observer<T>
类型的参数,Kotlin认为Observer是androidx.lifecycle库中用Java编写的**functional interface**。您传递的是
(List<MusicFile>) -> Unit
类型。这是一个高阶函数,与
Observer<List<MusicFile>>
的类型不同,它们在功能上相似,都有一个List<MusicFile>
类型的参数,并且都返回Unit
,所以Kotlin做的是更好还是更坏(在本例中更坏),它会为你“强制转换”类型。当Kotlin从高阶函数“强制转换”到函数接口时,它正在创建一个新对象。每次在代码中调用observeForever或removeObserver时都会发生这种情况。这就是removeObserver不工作的原因,因为不管代码看起来如何,实际上你并没有传入相同的对象。I've written about this before.
简而言之,您可以通过将观察者的类型更改为“观察者”来解决问题: