[英]Android viewmodel pass parameter to view model from view
I have a Fragment code -我有一个片段代码 -
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, {
// ...
})
}
I have a ViewModel code -我有一个 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)
As you see in my ViewModel, I am at the moment hardcoding the id in PetAction.GetPetDetails("2")
which is not correct.正如您在我的 ViewModel 中看到的,我目前正在对
PetAction.GetPetDetails("2")
中的 id 进行硬编码,这是不正确的。
How do I pass the id from my view to viewModel?如何将 id 从我的视图传递给 viewModel?
You have two options, if the petId
(from the Fragment) does not change, you could create / inject your ViewModel and pass the petId
via Constructor.您有两个选择,如果
petId
(来自 Fragment)没有改变,您可以创建/注入您的 ViewModel 并通过构造函数传递petId
。
Can your petId
be null
?您的
petId
可以是null
吗? If not you can then directly initialize your LiveData and observe it from your Fragment.如果没有,您可以直接初始化您的 LiveData 并从您的片段中观察它。
class PetViewModel(petId: String): ViewModel() {
val petDetailsLiveData = petService.performPetAction(PetAction.GetPetDetails(petId)).map {
// ...
}.asLiveData(Dispatchers.Default + viewModelScope.coroutineContext)
}
Second option, as you showed in your question, if petId
can change, create the LiveData within the function getPetDetailsForId(id: String?)
.第二个选项,正如您在问题中显示的那样,如果
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)
}
After discussion讨论后
You can consider some caching of your petId
and the PetDetailsViewState
to avoid duplicate api calls.您可以考虑对您的
petId
和PetDetailsViewState
进行一些缓存,以避免重复的 api 调用。 Take this aa very simple example of getting the idea.以这个非常简单的例子来理解这个想法。 There is much to improve here.
这里有很多需要改进的地方。
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)
}
}
}
Found a way to do with savedStateHandle
-找到了一种方法来处理
savedStateHandle
-
Here is my Fragment -这是我的片段-
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.petDetailsViewData.observe(viewLifecycleOwner, {
})
}
ViewModel -视图模型 -
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)
}
I basically use safeArgs key inside viewModel and access it via savedStateHandle.我基本上在 viewModel 中使用 safeArgs 键并通过 savedStateHandle 访问它。 This way I don't need to bother my view with accessing ids and also on configuration change, I only call my service once.
这样我就不需要访问 id 和配置更改来打扰我的视图,我只调用我的服务一次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.