我正在创建一个扩展BottomSheetDialogFragment的对话框。在这个对话框中,我有一个ViewModel来保存片段的状态(它里面有一些输入)。ViewModel的一些属性是LiveData。我注意到,当取消对话框(调用dismiss()或在对话框外部点击)并重新打开它时,LiveData属性的值将保持不变。
因此,作为一种解决方案,我想重写onDismiss()事件来手动清除ViewModel中的数据:
override fun onDismiss(dialog: DialogInterface) {
// Clear the viewmodel
viewModel.clear()
viewModelStore.clear()
super.onDismiss(dialog)
// Unsubscribe from observer
viewModel.getContact().removeObservers(viewLifecycleOwner)
}viewModel.clear()是我的ViewModel中的一个函数,它将内部的数据重置为默认值。
显然,这也是不够的,因为即使在解雇之前重置ViewModel中的数据之后,当重新打开对话框时,ViewModel仍然保存它在调用clear()之前保存的数据。
因为不是LiveData的属性是重置的,所以我相信有一种特定的方法可以重新设置LiveData值,但是我不知道如何做。有人能帮我吗?提前感谢!
发布于 2020-08-25 13:16:53
禤浩焯好心地向我提供了他的项目样本。此答案基于调试示例项目的结果。
引起问题的问题实际上位于MainActivity类中。在活动的AddReminderFragment方法中实例化onCreate,当按下FAB时,显示该片段的实例。
一切看起来都很好,除了-,您总是呈现的相同实例。这意味着当您第一次呈现这个片段时,您将得到一个全新的AddReminderViewModel,它是使用by viewModels()懒散加载的。
最初,我认为延迟加载by viewModels()导致了这个问题,因为它使用片段本身作为视图模型存储,而缓存的创建了视图模型,以防您以后要重用它。事实并非如此。
如何解决这个问题?
从不存储对活动和片段的引用(),也从不尽可能地避免引用,并且在有引用时要小心。它可能会导致内存泄漏。
简短地描述了我所做的事情:
private lateinit var modal: AddReminderFragment中删除MainActivity变量;ITimePipupCallback中去除MainActivity;onAttach(context: Context)中去除TimePopupFragment;fun setCallback(callback: ITimePipupCallback): TimePopupFragment中实现了TimePopupFragment;AddReminderFragment的AddReminderFragment实例之前,传入回调ITimePipupCallback实例。仿佛它是对AlertDialog按钮单击的回调;onTimePicked和onDayPicked方法从AddReminderFragment中删除,因为它们不再需要。更新的MainActivity
class MainActivity : AppCompatActivity() {
companion object {
const val AddReminderModalTag = "add_reminder_modal"
}
private lateinit var binding: MainActivityBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = MainActivityBinding.inflate(layoutInflater)
binding.showModalHandler = this
setContentView(binding.root)
}
fun showAddReminderModal(view: View) {
AddReminderFragment.newInstance().show(supportFragmentManager, AddReminderModalTag)
}
}对AddReminderFragment进行的更新
class AddReminderFragment : BottomSheetDialogFragment() {
...
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
...
//Bind the add time button
binding.addTimeButton.setOnClickListener {
TimePopupFragment
.newInstance(viewModel.getReminderType().value!!)
.setCallback(object : ITimePipupCallback {
override fun onTimePicked(hour: Int, minute: Int) {
viewModel.addTimeToRemind(hour, minute)
}
override fun onDayPicked(day: Int) {
viewModel.addTimeToRemind(day)
}
})
.show(
parentFragmentManager,
TIME_PICKER_TAG
)
}
...
return binding.root
}
...
}对TimePopupFragment进行的更新
class TimePopupFragment : DialogFragment() {
...
private lateinit var callback: ITimePipupCallback
// Removed `onAttach` method
fun setCallback(callback: ITimePipupCallback): TimePopupFragment {
this.callback = callback
return this
}
...
}您可以安全地从override fun onDismiss(dialog: DialogInterface)中删除AddReminderFragment。
发布于 2020-08-25 09:47:28
确保您使用的是片段的视图模型。您不应该通过向活动数据postValue(T value)提交值来清除视图模型,因为这是不必要的。
使用以下视图模型,
class MyViewModel : ViewModel() {
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}在DialogFragment中,将视图模型初始化为
ViewModelProviders.of(<FRAGMENTT>).get(MyViewModel.class);如果您使用的是ktx,则通过
// Get a reference to the ViewModel scoped to this Fragment
val viewModel by viewModels<MyViewModel>()https://stackoverflow.com/questions/63575585
复制相似问题