[英]Pass parameter WeakReference<View> to method of ViewModel?
[英]Android viewmodel pass parameter to view model from view
我有一个片段代码 -
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val safeArgs: PetDetailsViewArgs by navArgs()
val petId = safeArgs.petId
viewModel.getPetDetailsForId(petId).observe(viewLifecycleOwner, {
// ...
})
}
我有一个 ViewModel 代码 -
private val viewState = PetDetailsViewState()
fun getPetDetailsForId(id: String?): LiveData<PetDetailsViewState> {
return if (id.isNullOrEmpty()) {
liveData {
emit(
viewState.copy(
loading = false,
error = ErrorType.PET_ID_NULL_OR_EMPTY
)
)
}
} else {
petDetailsLiveData
}
}
var petDetailsLiveData = petService.performPetAction(PetAction.GetPetDetails("2")).map {
when (it) {
// ...
}
}.asLiveData(Dispatchers.Default + viewModelScope.coroutineContext)
正如您在我的 ViewModel 中看到的,我目前正在对PetAction.GetPetDetails("2")
中的 id 进行硬编码,这是不正确的。
如何将 id 从我的视图传递给 viewModel?
您有两个选择,如果petId
(来自 Fragment)没有改变,您可以创建/注入您的 ViewModel 并通过构造函数传递petId
。
您的petId
可以是null
吗? 如果没有,您可以直接初始化您的 LiveData 并从您的片段中观察它。
class PetViewModel(petId: String): ViewModel() {
val petDetailsLiveData = petService.performPetAction(PetAction.GetPetDetails(petId)).map {
// ...
}.asLiveData(Dispatchers.Default + viewModelScope.coroutineContext)
}
第二个选项,正如您在问题中显示的那样,如果petId
可以更改,请在 function getPetDetailsForId(id: String?)
中创建 LiveData。
fun getPetDetailsForId(id: String?): LiveData<PetDetailsViewState> {
return if (id.isNullOrEmpty()) {
liveData {
emit(
viewState.copy(
loading = false,
error = ErrorType.PET_ID_NULL_OR_EMPTY
)
)
}
} else {
petService.performPetAction(PetAction.GetPetDetails("2")).map {
// ...
}.asLiveData(Dispatchers.Default + viewModelScope.coroutineContext)
}
讨论后
您可以考虑对您的petId
和PetDetailsViewState
进行一些缓存,以避免重复的 api 调用。 以这个非常简单的例子来理解这个想法。 这里有很多需要改进的地方。
class PetViewModel : ViewModel() {
private val cachedPetDetailsViewState: PetDetailsViewState? = null
private val cachedPetId: String = ""
fun getPetDetailsForId(id: String?): LiveData<PetDetailsViewState> {
if (id == cachedPetId && cachedPetDetailsViewState != null) return MutableLiveData(cachedPetDetailsViewState)
cachedPetId == id
if (id.isNullOrEmpty() { ... }
else {
val petIdViewState = // make the API call
cachedPetDetailsViewState = petIdViewState
return MutableLiveData(petIdViewState)
}
}
}
找到了一种方法来处理savedStateHandle
-
这是我的片段-
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.petDetailsViewData.observe(viewLifecycleOwner, {
})
}
视图模型 -
class PetDetailsViewModel @ViewModelInject constructor(
private val petService: PetService,
@Assisted private val savedStateHandle: SavedStateHandle
) :
ViewModel() {
private val viewState = PetDetailsViewState()
var petDetailsViewData =
petService.performPetAction(PetAction.GetPetDetails(savedStateHandle.get<String>("petId")!!))
.map {
when (it) {
// ...
}
}.asLiveData(Dispatchers.Default + viewModelScope.coroutineContext)
}
我基本上在 viewModel 中使用 safeArgs 键并通过 savedStateHandle 访问它。 这样我就不需要访问 id 和配置更改来打扰我的视图,我只调用我的服务一次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.