gpt4 book ai didi

android - LiveData 无法观察到变化

转载 作者:行者123 更新时间:2023-12-02 12:11:33 25 4
gpt4 key购买 nike

我正在更新 ViewModel 中 DialogFragment 的 LiveData 值 ,但无法获取 Fragment 中的值。

View 模型:

class OtpViewModel(private val otpUseCase: OtpUseCase, analyticsModel: IAnalyticsModel) : BaseViewModel(analyticsModel) {
override val globalNavModel = GlobalNavModel(titleId = R.string.otp_contact_title, hasGlobalNavBar = false)

private val _contactListLiveData = MutableLiveData<List<Contact>>()
val contactListLiveData: LiveData<List<Contact>>
get() = _contactListLiveData

private lateinit var cachedContactList: LiveData<List<Contact>>
private val contactListObserver = Observer<List<Contact>> {
_contactListLiveData.value = it
}



private lateinit var cachedResendOtpResponse: LiveData<LogonModel>
private val resendOTPResponseObserver = Observer<LogonModel> {
_resendOTPResponse.value = it
}

private var _resendOTPResponse = MutableLiveData<LogonModel>()
val resendOTPResponseLiveData: LiveData<LogonModel>
get() = _resendOTPResponse

var userSelectedIndex : Int = 0 //First otp contact selected by default

val selectedContact : LiveData<Contact>
get() = MutableLiveData(contactListLiveData.value?.get(userSelectedIndex))

override fun onCleared() {
if (::cachedContactList.isInitialized) {
cachedContactList.removeObserver(contactListObserver)
}

if (::cachedOtpResponse.isInitialized) {
cachedOtpResponse.removeObserver(otpResponseObserver)
}

super.onCleared()
}

fun updateIndex(pos: Int){
userSelectedIndex = pos
}

fun onChangeDeliveryMethod() {
navigate(
OtpVerificationHelpCodeSentBottomSheetFragmentDirections
.actionOtpContactVerificationBottomSheetToOtpChooseContactFragment()
)
}

fun onClickContactCancel() {
navigateBackTo(R.id.logonFragment, true)
}

fun retrieveContactList() {
cachedContactList = otpUseCase.fetchContactList()
cachedContactList.observeForever(contactListObserver)
}



fun resendOTP(contactId : String){
navigateBack()
cachedResendOtpResponse = otpUseCase.resendOTP(contactId)
cachedResendOtpResponse.observeForever(resendOTPResponseObserver)

}
}

BaseViewModel:
abstract class BaseViewModel(val analyticsModel: IAnalyticsModel) : ViewModel() {
protected val _navigationCommands: SingleLiveEvent<NavigationCommand> = SingleLiveEvent()
val navigationCommands: LiveData<NavigationCommand> = _navigationCommands

abstract val globalNavModel: GlobalNavModel


/**
* Posts a navigation event to the navigationsCommands LiveData observable for retrieval by the view
*/
fun navigate(directions: NavDirections) {
_navigationCommands.postValue(NavigationCommand.ToDirections(directions))
}

fun navigate(destinationId: Int) {
_navigationCommands.postValue(NavigationCommand.ToDestinationId(destinationId))
}

fun navigateBack() {
_navigationCommands.postValue(NavigationCommand.Back)
}

fun navigateBackTo(destinationId: Int, isInclusive: Boolean) {
_navigationCommands.postValue(NavigationCommand.BackTo(destinationId, isInclusive))
}

open fun init() {
// DEFAULT IMPLEMENTATION - override to initialize your view model
}


/**
* Called from base fragment when the view has been created.
*/
fun onViewCreated() {
analyticsModel.onNewState(getAnalyticsPathCrumb())
}

/**
* gets the Path for the current page to be used for the trackstate call
*
* Override this method if you need to modify the path
*
* the page id for the track state call will be calculated in the following manner
* 1) analyticsPageId
* 2) titleId
* 3) the page title string
*/
protected fun getAnalyticsPathCrumb() : AnalyticsBreadCrumb {

return analyticsBreadCrumb {
pathElements {
if (globalNavModel.analyticsPageId != null) {
waPath {
path = PathElement(globalNavModel.analyticsPageId as Int)
}
} else if (globalNavModel.titleId != null) {
waPath {
path = PathElement(globalNavModel.titleId as Int)
}
} else {
waPath {
path = PathElement(globalNavModel.title ?: "")
}
}
}
}
}
}

对话 fragment :

class OtpVerificationHelpCodeSentBottomSheetFragment : BaseBottomSheetDialogFragment(){

private lateinit var rootView: View
lateinit var binding: BottomSheetFragmentOtpVerificationHelpCodeSentBinding

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

viewModel = getViewModel<OtpViewModel>()

binding = DataBindingUtil.inflate(inflater, R.layout.bottom_sheet_fragment_otp_verification_help_code_sent, container, false)

rootView = binding.root

return rootView
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)


val otpViewModel = (viewModel as OtpViewModel)
binding.viewmodel = otpViewModel

otpViewModel.resendOTPResponseLiveData.observe(viewLifecycleOwner, Observer {

it?.let { resendOtpResponse ->
if(resendOtpResponse.statusCode.equals("000")){
//valid status code
requireActivity().toastMessageOtp(getString(R.string.otp_code_verification_sent))
}else{
//show the error model
//it?.errorModel?.let { it1 -> handleDiasNetworkError(it1) }
}
}

})
}
}

我调用 重新发送OTP(contactId : String) 的 xml 文件中 View 模型的方法对话 fragment :
 <TextView
android:id="@+id/verification_help_code_sent_resend_code"
style="@style/TruTextView.SubText2.BottomActions"
android:layout_height="@dimen/spaceXl"
android:gravity="center_vertical"
android:text="@string/verification_help_resend_code"
android:onClick="@{() -> viewmodel.resendOTP(Integer.toString(viewmodel.userSelectedIndex))}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/top_guideline" />

现在,每当我尝试从 Fragment 调用 resendOTPResponseLiveData 时,它都不会被调用:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Log.d("OtpVerify" , "OnViewCreatedCalled")
viewModel.onViewCreated()
val otpViewModel = (viewModel as OtpViewModel)

binding.lifecycleOwner = this
binding.viewmodel = otpViewModel
binding.toAuthenticated = OtpVerifyFragmentDirections.actionOtpVerifyFragmentToAuthenticatedActivity()
binding.toVerificationBtmSheet = OtpVerifyFragmentDirections.actionOtpVerifyFragmentToOtpContactVerificationCodeSentBottomSheet()


otpViewModel.resendOTPResponseLiveData.observe(viewLifecycleOwner, Observer {
if(it?.statusCode.equals("000")){
//valid status code
requireActivity().toastMessageOtp(getString(R.string.otp_code_verification_sent))
}else{
//show the error model
it?.errorModel?.let { it1 -> handleDiasNetworkError(it1) }
}
})

}

那么我在这里做错了什么。

编辑

基本上我需要在dialogfragment中单击listener(重新发送按钮单击),并且需要在 fragment 中读取它。所以我使用了 SharedViewModel 的概念。

因此,我在 ViewModel 中进行了必要的更改:
private val selected = MutableLiveData<LogonModel>()

fun select(logonModel: LogonModel) {
selected.value = logonModel
}

fun getSelected(): LiveData<LogonModel> {
return selected
}

在 DialogFragment 中:
 otpViewModel.resendOTPResponseLiveData.observe(viewLifecycleOwner, Observer{

otpViewModel.select(it);

})

在我想读取值的 fragment 中:
otpViewModel.getSelected().observe(viewLifecycleOwner, Observer {

Log.d("OtpVerify" , "ResendCalled")
// Update the UI.
if(it?.statusCode.equals("000")){
//valid status code
requireActivity().toastMessageOtp(getString(R.string.otp_code_verification_sent))
}else{
//show the error model
it?.errorModel?.let { it1 -> handleDiasNetworkError(it1) }
}
})

但它仍然无法正常工作。

编辑:

fragment 的 ViewModel 源:
viewModel = getSharedViewModel<OtpViewModel>(from = {
Navigation.findNavController(container as View).getViewModelStoreOwner(R.id.two_step_authentication_graph)
})

对话框 fragment 的 ViewModel 源:
viewModel = getViewModel<OtpViewModel>()

最佳答案

如果我理解正确的话,几个月前作为 Jetpack 库和 Kotlin 的新手,我遇到了类似的问题。

我认为这里的问题是您正在使用 by viewModels 检索 ViewModel这意味着您返回的 ViewModel 将仅限于当前 fragment 上下文...如果您想在应用程序的多个部分共享 View 模型,则它们必须是 Activity 范围的。

例如:

//this will only work for the current fragment, using this declaration here and anywhere else and observing changes wont work, the observer will never fire, except if the method is called within the same fragment that this is declared
private val viewModel: AddPatientViewModel by viewModels {
InjectorUtils.provideAddPatientViewModelFactory(requireContext())
}

//this will work for the ANY fragment in the current activies scope, using this code and observing anywhere else should work, the observer will fire, except if the method is called fro another activity
private val patientViewModel: PatientViewModel by activityViewModels {
InjectorUtils.providePatientViewModelFactory(requireContext())
}

注意我的 viewModel类型 AddPatientViewModel仅通过 viewModel: XXX by viewModels 作用于当前 fragment 上下文,对该特定 ViewModel 所做的任何更改等都只会在我当前的 fragment 中传播。

其中 patientViewModel类型 PatientViewModel通过 patientViewModel: XXX by activityViewModels 作用于 Activity 上下文.
这意味着只要两个 fragment 属于同一个 Activity ,并且您通过 ... by activityViewModels 获得 ViewModel您应该能够在全局范围内观察对 ViewModel 所做的任何更改(全局意味着在声明它的同一 Activity 中的任何 fragment )。

考虑到以上所有情况,如果您的 viewModel 正确地限定在您的 Activity 范围内并且在两个 fragment 中您使用 by activityViewModels 检索 viewModel并更新通过 XXX.postValue(YYY) 观察到的值或 XXX.value = YYY您应该能够从同一 Activity 上下文中的任何位置观察对 ViewModel 所做的任何更改。

希望这是有道理的,现在已经很晚了,我就在我被解雇之前看到了这个问题!

关于android - LiveData 无法观察到变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62343552/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com