问题
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