簡體   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