Parcelable Model reinstatiates, MVVM Room LiveData

落花浮王杯 提交于 2021-02-11 14:01:17

问题


Here is my problem, I am using mvvm to load profile data from Dao, which was earlier updated when user logs in. Or if a new user an empty model loads. see my BasicProfileFragment and ViewModel.

I am using LiveData to update fragment from Dao initially. Next, I want to edit/update the fields in different ways. keyboard input and updating data by Navigating to other fragments. Where data loaded as list from server. For eg. clicking the Gender strip and Navigate to Gender Fragment, Data populated there. and select from list there and NavigateUp to BasicProfileFragment. The problem here is, when I am back to BasicProfileFragment data populated earlier via Dao disappears from the fields. But new data persists. I need to edit or correct earlier loaded data and sent back to the server and update the response in 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 class implementation

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
}

来源:https://stackoverflow.com/questions/61508187/parcelable-model-reinstatiates-mvvm-room-livedata

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!