首页
学习
活动
专区
圈层
工具
发布

安卓:
EN

Stack Overflow用户
提问于 2020-08-25 09:08:19
回答 2查看 1.8K关注 0票数 0

我正在创建一个扩展BottomSheetDialogFragment的对话框。在这个对话框中,我有一个ViewModel来保存片段的状态(它里面有一些输入)。ViewModel的一些属性是LiveData。我注意到,当取消对话框(调用dismiss()或在对话框外部点击)并重新打开它时,LiveData属性的值将保持不变。

因此,作为一种解决方案,我想重写onDismiss()事件来手动清除ViewModel中的数据:

代码语言:javascript
复制
 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值,但是我不知道如何做。有人能帮我吗?提前感谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-08-25 13:16:53

禤浩焯好心地向我提供了他的项目样本。此答案基于调试示例项目的结果。

引起问题的问题实际上位于MainActivity类中。在活动的AddReminderFragment方法中实例化onCreate,当按下FAB时,显示该片段的实例。

一切看起来都很好,除了-,您总是呈现的相同实例。这意味着当您第一次呈现这个片段时,您将得到一个全新的AddReminderViewModel,它是使用by viewModels()懒散加载的。

最初,我认为延迟加载by viewModels()导致了这个问题,因为它使用片段本身作为视图模型存储,而缓存的创建了视图模型,以防您以后要重用它。事实并非如此。

如何解决这个问题?

从不存储对活动和片段的引用(),也从不尽可能地避免引用,并且在有引用时要小心。它可能会导致内存泄漏。

简短地描述了我所做的事情:

  1. private lateinit var modal: AddReminderFragment中删除MainActivity变量;
  2. ITimePipupCallback中去除MainActivity
  3. onAttach(context: Context)中去除TimePopupFragment
  4. fun setCallback(callback: ITimePipupCallback): TimePopupFragment中实现了TimePopupFragment
  5. 在显示来自AddReminderFragmentAddReminderFragment实例之前,传入回调ITimePipupCallback实例。仿佛它是对AlertDialog按钮单击的回调;
  6. onTimePickedonDayPicked方法从AddReminderFragment中删除,因为它们不再需要。

更新的MainActivity

代码语言:javascript
复制
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进行的更新

代码语言:javascript
复制
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进行的更新

代码语言:javascript
复制
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

票数 2
EN

Stack Overflow用户

发布于 2020-08-25 09:47:28

确保您使用的是片段的视图模型。您不应该通过向活动数据postValue(T value)提交值来清除视图模型,因为这是不必要的。

使用以下视图模型,

代码语言:javascript
复制
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中,将视图模型初始化为

代码语言:javascript
复制
ViewModelProviders.of(<FRAGMENTT>).get(MyViewModel.class);

如果您使用的是ktx,则通过

代码语言:javascript
复制
// Get a reference to the ViewModel scoped to this Fragment
val viewModel by viewModels<MyViewModel>()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63575585

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档