繁体   English   中英

Android viewmodel 传递参数以查看 model 从视图

[英]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)
    }

讨论后

您可以考虑对您的petIdPetDetailsViewState进行一些缓存,以避免重复的 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM