Восстанавливаемая модель восстанавливается, MVVM Room LiveData - PullRequest
0 голосов
/ 29 апреля 2020

Вот моя проблема, я использую mvvm для загрузки данных профиля из Dao, который был ранее обновлен, когда пользователь входит в систему. Или, если новый пользователь загружает пустую модель. см. мой BasicProfileFragment и ViewModel.

Я использую LiveData для первоначального обновления фрагмента из Dao. Далее я хочу редактировать / обновлять поля разными способами. ввод с клавиатуры и обновление данных путем перехода к другим фрагментам. Где данные загружаются в виде списка с сервера. Например, щелкнув полосу Пол и перейдите к фрагменту Пол, там будут заполнены Данные. и выберите из списка там и перейдите к BasicProfileFragment. Проблема здесь в том, что когда я возвращаюсь к данным BasicProfileFragment, заполненным ранее через Dao, они исчезают с полей. Но новые данные сохраняются. Мне нужно отредактировать или исправить ранее загруженные данные и отправить обратно на сервер и обновить ответ в Dao.

My BasicProfileFragment

imports .....

class BasicProfileFragment : DaggerFragment() {
    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory
    private lateinit var basicProfileViewModel: BasicProfileViewModel
    private var filterEventHasBeenHandled = false

    companion object {
        const val FILTER_EVENT_HANDLED = "filterEventHasBeenHandled"
    }

    override fun onSaveInstanceState(outState: Bundle) {
        outState.run { putBoolean(FILTER_EVENT_HANDLED, filterEventHasBeenHandled) }
        super.onSaveInstanceState(outState)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        filterEventHasBeenHandled = savedInstanceState?.getBoolean(FILTER_EVENT_HANDLED) ?: false

        basicProfileViewModel = activityViewModel(viewModelFactory){
            observe(userDataState) { handleUserState(it) }
            observe(submitEvent, ::handleProfileEvent)
            observe(profileDataState) { handleDataState(it) }
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_basic_profile, container, false)
    }

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

        if (!filterEventHasBeenHandled) {
            val basicProfileModel =
                arguments?.getParcelable("basicProfileModel") ?: BasicProfileModel.empty()
           basicProfileViewModel.setProfile(basicProfileModel)
       }
        initializeView()


        if (basicProfileViewModel.obtainCurrentUser() == null) {
            val uid = Prefs.getString("USER_OID", "0")
            loadUser(uid)
            filterEventHasBeenHandled = true
        }
    }

    private fun initializeView() {
        (activity as AppCompatActivity).setSupportActionBar(toolbar)
        (activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true)
        toolbar.setPadding(0, (activity as MainActivity).getStatusBarHeight(), 0, 0)


        genderStrip.setOnClickListener {
            it.hideKeyboard()
            navigate(R.id.action_basicProfileFragment_to_gendersFragment)
        }


    private fun handleProfileEvent(submitEvent: Event<BasicProfileModel>?) {
        if (filterEventHasBeenHandled && submitEvent?.hasBeenHandled == true) {
            submitEvent.peekContent { renderProfileFields(it) }
        } else {
            submitEvent?.getContentIfNotHandled {
                renderProfileFields(it)
                filterEventHasBeenHandled = true
            }
        }
    }

    private fun handleUserState(userDataState: DataState<BasicProfileModel>?) { .... }


    private fun handleDataState(profileDataState: DataState<BasicProfileModel>?) {....}


    private fun handleError(exception: Exception) {.... }


    private fun applySubmit(basicProfileModel: BasicProfileModel){
        basicProfileViewModel.submitProfile(basicProfileModel)
    }

    private fun handleUserError(exception: Exception) {....}


    private fun updatedFields(basicProfileModel: BasicProfileModel){
        context?.onSuccess(R.string.updation_success)
        renderProfileFields(basicProfileModel)
    }


    private fun renderProfileFields(basicProfileModel: BasicProfileModel) {

        renderGender(basicProfileModel.genderModel)
    }

    private fun renderGender(genderModel: GenderModel?) {
        genderModel?.let {
            tvGender.visible()
            tvGender.text = it.gender
        } ?: tvGender.gone()
    }
}

My ViewModel

imports....


class BasicProfileViewModel @Inject constructor(private val basicProfileUseCase: BasicProfileUseCase,
    private val getUserUseCase: GetUserUseCase) : ViewModel() {

    private val _profileDataState = MutableLiveData<DataState<BasicProfileModel>>()
    val profileDataState: LiveData<DataState<BasicProfileModel>>
        get() = _profileDataState

    private val _userDataState = MutableLiveData<DataState<BasicProfileModel>>()
    val userDataState: LiveData<DataState<BasicProfileModel>>
        get() = _userDataState

    private var _applySubmitEvent = MutableLiveData<Event<Any>>()
    val applySubmitEvent: LiveData<Event<Any>>
        get() = _applySubmitEvent

    private var _submitEvent = MutableLiveData<Event<BasicProfileModel>>()
    val submitEvent: LiveData<Event<BasicProfileModel>>
        get() = _submitEvent

    private var profile = userDataState.value?.data ?: BasicProfileModel.empty()

    fun setGender(genderModel: GenderModel) {
        profile.genderModel = genderModel
        this._submitEvent.value = Event(profile)
    }

    fun setProfile(basicProfileModel: BasicProfileModel) {
        this.profile = basicProfileModel.copy()
        this._submitEvent.value = Event(profile)
    }

    fun applySubmit() {
        this._sharedFilter.value = Event(profile)
        this._applySubmitEvent.value = Event(Any())
        submitProfile(profile)
    }

    // for updating via NetworkDatastore
    fun submitProfile(basicProfileModel: BasicProfileModel){
        this.profile = basicProfileModel.copy()

        launchAsync {
            try {
                val profileModel = asyncAwait {
                    BasicProfileModel(basicProfileUseCase.run(
                            profile.genderModel?.gender,
                            profile.genderModel?.genderCode))
                }
                _profileDataState.value = DataState.Success(profileModel)
            } catch (exception: Exception) {
                _profileDataState.value = DataState.Error(exception, obtainCurrentData())
            }
        }
    }

    fun obtainCurrentData() = _profileDataState.value?.data

    // for updating via Dao
    fun loadUser(uid: String) {
        launchAsync {
            try {
                val profileUser = asyncAwait { BasicProfileModel(getUserUseCase.run(uid)) }
                _userDataState.value = DataState.Success(profileUser)
            } catch (exception: Exception) {
                _userDataState.value = DataState.Error(exception, obtainCurrentUser())
            }
        }
    }

   fun obtainCurrentUser() = _userDataState.value?.data

}

Реализация класса My Event

open class Event<out T>(private val content: T) {

    var hasBeenHandled = false
        private set // Allow external read but not write


    // Returns the content and prevents its use again.
    fun getContentIfNotHandled(consumer: (T) -> Unit) {
        if (!hasBeenHandled) {
            hasBeenHandled = true
            consumer(content)
        }
    }

     //Returns the content, even if it's already been handled.
    fun peekContent(consumer: (T) -> Unit) = consumer(content)

     // Returns the content, even if it's already been handled.
    fun peekContent() = content
}
...