问题描述
LeakCanary 告诉我我的一个 viewmodel 正在泄漏,但玩了 2 天后我无法让泄漏消失。
viewmodel = viewmodelProvider(this).get(ViewBreederviewmodel::class.java).apply {
getStrains(arguments?.getString(BREEDER_ID_KEY,"")!!)
}
这是视图模型
class ViewBreederviewmodel(application: Application) : Androidviewmodel(application) {
private val breederRepository = BreederRepository(application)
val strainList = mutablelivedata<List<MinimalStrain>>()
fun getStrains(breederId: String) {
viewmodelScope.launch {
breederRepository.getMinimalStrains(breederId).observeForever {
strainList.value = it
}
}
}
}
这是 BreederRepository:
class BreederRepository(context: Context) {
private val dao: BreederDao
private val breederApi = RetrofitClientInstance.getInstance(context).breederAndStrainIdsApi
init {
val database: Db = Db.getInstance(
context
)!!
dao = database.breederDao()
}
suspend fun getMinimalStrains(breederId: String): LiveData<List<MinimalStrain>> =
withContext(dispatchers.IO) {
dao.getMinimalStrains(breederId)
}
}
这里是 Db 类
@Database(
entities = [Breeder::class,Strain::class],version = 1,exportSchema = true)
@TypeConverters(RoomDateConverter::class)
abstract class Db : RoomDatabase() {
abstract fun breederDao(): BreederDao
companion object {
private var instance: Db? = null
@JvmStatic
fun getInstance(context: Context): Db? {
if (instance == null) {
synchronized(Db::class) {
instance = Room.databaseBuilder(
context.applicationContext,Db::class.java,"seedfinder_db"
)
.build()
}
}
return instance
}
}
}
解决方法
您正在使用 end=""
,顾名思义,即使在您的 ViewModel 被清除后,它也会永远保持观察。 Room 不需要为返回 observeForever
的 DAO 方法使用 suspend
方法,这在任何情况下都不是正确的方法 - LiveData
已经是异步的。
相反,您应该是 transforming your LiveData,使用您的 LiveData
作为您的 breederId
LiveData 的输入:
strainList
您的 class ViewBreederViewModel(application: Application) : AndroidViewModel(application) {
private val breederRepository = BreederRepository(application)
private val currentBreederId = MutableLiveData<String>()
// Here we use the switchMap method from the lifecycle-livedata-ktx artifact
val strainList: LiveData<String> = currentBreederId.switchMap {
breederId -> breederRepository.getMinimalStrains(breederId)
}
private fun setBreederId(breederId: String) {
currentBreederId.value = breederId
}
}
的位置:
getMinimalStrains
您可以通过在 UI 中设置 fun getMinimalStrains(breederId: String): LiveData<List<MinimalStrain>> =
dao.getMinimalStrains(breederId)
并像以前一样观察 breederId
来使用它:
strainList
如果您使用 Saved State module for ViewModels(如果您使用最新的稳定 Fragments / Activity 库,这是默认设置),那么您可以使用 viewModel = ViewModelProvider(this).get(ViewBreederViewModel::class.java).apply {
setBreederId(arguments?.getString(BREEDER_ID_KEY,"")!!)
}
viewModel.strainList.observe(viewLifecycleOwner) { strainList ->
// use your updated list
}
,它会根据您的 Fragment 的参数自动填充并完全跳过 SavedStateHandle
:
setBreederId()
这意味着您的代码可以简单地变成:
class ViewBreederViewModel(
application: Application,savedStateHandle: SavedStateHandle
) : AndroidViewModel(application) {
private val breederRepository = BreederRepository(application)
// Here we use the switchMap method from the lifecycle-livedata-ktx artifact
val strainList: LiveData<String> = savedStateHandle
.getLiveData(BREEDER_ID_KEY) // Automatically populated from arguments
.switchMap {
breederId -> breederRepository.getMinimalStrains(breederId)
}
}
如果您使用 viewModel = ViewModelProvider(this).get(ViewBreederViewModel::class.java)
viewModel.strainList.observe(viewLifecycleOwner) { strainList ->
// use your updated list
}
工件,您可以将其进一步简化为:
fragment-ktx