LiveData无法观察到变化

问题描述 投票:1回答:2

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

The ViewModel:

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)

    }
}

The 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 ?: "")
                    }
                }
            }
        }
    }
}

The DialogFragment:

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) }
                }
            }

        })
    }
}

我正在从DialogFragment的xml文件中调用viewmodel的resendOTP(contactId:String)方法。

 <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中单击clicklistener(重新发送按钮单击),并需要在片段中读取它。因此,我使用了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);

        })

并且在我要读取值的片段中:

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) }
            }
        })

但是它仍然无法正常工作。

编辑:

片段的ViewModel源:

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

对话框片段的ViewModel源:

viewModel = getViewModel<OtpViewModel>()
    

我正在从ViewModel的DialogFragment更新LiveData值,但无法在Fragment中获取该值。 ViewModel:类OtpViewModel(priv val otpUseCase:OtpUseCase,analyticsModel:...

android kotlin mvvm android-databinding android-livedata
2个回答
0
投票

问题是您实际上没有在Fragment


0
投票

[我认为这里的问题是您使用的是viewModels,这意味着您返回的ViewModel仅限于当前上下文/片段...如果您希望在应用程序的多个部分之间共享视图模型它们必须在活动范围内。

© www.soinside.com 2019 - 2024. All rights reserved.