Живые данные снова дают старое значение при смене фрагмента - PullRequest
1 голос
/ 16 апреля 2020

Я использую живые данные из общей ViewModel по нескольким фрагментам. У меня есть фрагмент для входа, который принимает номер телефона и пароль пользователя, а затем пользователь нажимает кнопку входа. Я вызываю API для этого, теперь, если вход не удается, я показываю тост «Вход не выполнен», теперь, если пользователь переходит к экрану «ForgotPassword», который также использует ту же модель представления, что и «SignInFragment», и нажимает обратно с экрана «забытого пароля», он приходит к фрагменту входа, но снова показывает всплывающее окно «Ошибка входа», но API не вызывается, он получает данные от ранее зарегистрированного наблюдателя, так есть ли способ это исправить?

SignInFragment.kt

class SignInFragment : Fragment() {

    private lateinit var binding: FragmentSignInBinding

    //Shared view model across two fragments
    private val onBoardViewModel by activityViewModels<OnBoardViewModel>()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = DataBindingUtil.inflate(
            inflater,
            R.layout.fragment_sign_in,
            container,
            false
        )
        return binding.root
    }

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

        onBoardViewModel.signInResponse.observe(viewLifecycleOwner) { response ->
            //This is calling again after coming back from new fragment it.
            showToast("Sign In Failed")
        }
    }

    override fun onClick(v: View?) {
        when (v?.id!!) {
            R.id.forgotPasswordTV -> {
                findNavController().navigate(SignInFragmentDirections.actionSignInFragmentToForgotPasswordFragment())
            }
            R.id.signInTV -> {
                val phoneNumber = binding.phoneNumberET.text
                val password = binding.passwordET.text
                val signInRequestModel = SignInRequestModel(
                    phoneNumber.toString(),
                    password.toString(),
                    ""
                )

                //Calling API for the sign-in
                onBoardViewModel.callSignInAPI(signInRequestModel)
            }
        }
    }
}

ForgotPasswordFragment

class ForgotPasswordFragment : Fragment() {

    private lateinit var binding: FragmentForgotPasswordBinding

    //Shared view model across two fragments
    private val onBoardViewModel by activityViewModels<OnBoardViewModel>()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = DataBindingUtil.inflate(
            inflater,
            R.layout.fragment_forgot_password,
            container,
            false
        )
        return binding.root
    }
}

OnBoardViewModel

class OnBoardViewModel : ViewModel() {

    private var repository: OnBoardRepository = OnBoardRepository.getInstance()

    private val signInRequestLiveData = MutableLiveData<SignInRequestModel>()

    //Observing this data in sign in fragment
    val signInResponse: LiveData<APIResource<SignInResponse>> =
        signInRequestLiveData.switchMap {
            repository.callSignInAPI(it)
        }

    //Calling this function from sign in fragment
    fun callSignInAPI(signInRequestModel: SignInRequestModel) {
        signInRequestLiveData.value = signInRequestModel
    }

    override fun onCleared() {
        super.onCleared()
        repository.clearRepo()
    }
}

Я пытался переместить этот код в onActivityCreated, но он все еще вызывается после возвращения из нового фрагмента.

 onBoardViewModel.signInResponse.observe(viewLifecycleOwner) { response ->
            showToast("Sign In Failed")
        }

Ответы [ 2 ]

0 голосов
/ 16 апреля 2020

Я бы предоставил способ сброса ваших живых данных. Дайте этому обнуляемый тип. Ваши наблюдатели могут игнорировать это, когда они получают нулевое значение. Вызывайте эту функцию при получении данных для входа в систему, чтобы вы также не повторяли сообщения при повороте экрана.

class OnBoardViewModel : ViewModel() {

    // ...

    fun consumeSignInResponse() {
        signInRequestLiveData.value = null
    }

}
onBoardViewModel.signInResponse.observe(viewLifecycleOwner) { response ->
    if (response != null) {
        showToast("Sign In Failed")
        onBoardViewModel.consumeSignInResponse()
    }
}
0 голосов
/ 16 апреля 2020

Использование класса SingleLiveEvent вместо LiveData в классе OnBoardViewModel решит вашу проблему:

val signInResponse: SingleLiveEvent <APIResource<SignInResponse>>.

class SingleLiveEvent<T> : MutableLiveData<T>() {

    private val pending = AtomicBoolean(false)

    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        super.observe(owner, Observer<T> { t ->
            if (pending.compareAndSet(true, false)) {
                observer.onChanged(t)
            }
        })
    }

    override fun setValue(t: T?) {
        pending.set(true)
        super.setValue(t)
    }

    fun call() {
        postValue(null)
    }

}

Это наблюдаемая с учетом жизненного цикла, что отправляет только новые обновления после подписки. LiveData вызывает только наблюдаемое, если есть явный вызов setValue () или call ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...