kotlin 未删除LiveData观察器

ig9co6j1  于 2023-01-02  发布在  Kotlin
关注(0)|答案(1)|浏览(191)

我试图在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属性显示观察者仍然是附着的。
我实际上如何删除观察者?

mspsb9vt

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.
简而言之,您可以通过将观察者的类型更改为“观察者”来解决问题:

private val observer: Observer<List<MusicFile>> =
    Observer { musicFiles: List<MusicFile> ->
        // _uiState.postValue(FragmentMusicListState(musicFiles))
    }

相关问题