当前位置: 首页 > 知识库问答 >
问题:

碎片。getViewLifeCycleOwner不阻止多次调用LiveData Observer

晋鹤轩
2023-03-14

当切换回第一个选项卡时,我需要注意不要再次返回数据!我做错了什么?你能帮帮我吗?

附言。对于导航,我使用navigation-advanced-sample中的sample,在切换选项卡后,不调用ondestroy

文章中的第一个解决方案是在片段中观察ViewModel中的LiveData:

一个合适的解决方案是使用getViewLifeCycleOwner()作为LifeCycleOwer,同时观察onActivityCreated中的LiveData,如下所示。

我使用以下代码,但对我不起作用:

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    Timber.d("onActivityCreated")
    viewModel.getProfileLive().observe(viewLifecycleOwner, observer)
}
class ProfileFragment : DaggerFragment() {

    @Inject
    lateinit var viewModel: ProfileFragmentViewModel

    private val observer = Observer<Resource<Profile>> {
        when (it.status) {
            Resource.Status.LOADING -> {
                Timber.i("Loading...")
            }
            Resource.Status.SUCCESS -> {
                Timber.i("Success: %s", it.data)
            }
            Resource.Status.ERROR -> {
                Timber.i("Error: %s", it.message)
            }
        }
    };

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Timber.d("onCreate")
    }

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

    fun <T> LiveData<T>.reObserve(owner: LifecycleOwner, observer: Observer<T>) {
        removeObserver(observer)
        observe(owner, observer)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        Timber.d("onViewCreated")
        viewModel.getProfileLive().observe(viewLifecycleOwner, observer)
        // viewModel.getProfileLive().reObserve(viewLifecycleOwner, observer)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        Timber.d("onActivityCreated")
    }

    override fun onDestroyView() {
        super.onDestroyView()
        Timber.d("onDestroyView")
        // viewModel.getProfileLive().removeObserver(observer)
    }

    override fun onDestroy() {
        super.onDestroy()
        Timber.d("onDestroy")
    }

    override fun onDetach() {
        super.onDetach()
        Timber.d("onDetach")
    }
}
class ProfileFragmentViewModel @Inject constructor(
    private val profileUseCase: ProfileUseCase
) : ViewModel() {

    init {
        Timber.d("Init profile VM")
    }

    fun getProfileLive() = profileUseCase.getProfile()
}
class ProfileUseCase @Inject constructor(
    private val profileRepository: ProfileRepository
) {

    fun getProfile(): LiveData<Resource<Profile>> {
        return profileRepository.getProfile()
    }
}

profilerepository.kt类ProfileRepository@inject构造函数(私有val LoginUserDao:LoginUserDao,私有val ProfileDao:ProfileDao,){

fun getProfile(): LiveData<Resource<Profile>> =
    liveData(Dispatchers.IO)
    {
        emit(Resource.loading(data = null))

        val profile = profileDao.getProfile()

        // Emit Success result...
    }

}

共有1个答案

罗祺
2023-03-14

这是因为碎片生命周期是如何工作的。当您来回移动一个片段时,onviewCreate()再次被调用。在onviewcreated中,调用viewmodel.getprofilelive(),从存储库返回livedata并对其进行观察。

因为每次移动回片段时都会调用onviewcreated(),所以对viewmodel.getprofilelive()的调用也是如此,然后再次调用存储库,这再次触发片段中的Observe方法。

为了解决这个问题,在ViewModel中创建一个LiveData变量,将其设置为从存储库返回的Live Data。在这个片段中,观察ViewModel的LiveData变量,而不是从存储库返回的那个变量。这样,您的Observe方法将在第一次触发,并且仅当来自存储库的数据值发生变化时触发。

 类似资料:
  • 我有一个动作和一个碎片。活动没有膨胀的菜单,而片段有一个带有两个按钮的菜单。片段菜单是可见的,但按钮没有任何反应时,轻点。在调试过程中,我可以看到Fragment和Activity的onCreateOptionsMenu()都被调用,但是当点击按钮时,没有onOptionsItemSelected()被调用,既没有从Activity调用,也没有从Fragment调用。

  • 问题内容: Ajax使用回调,因为它是同步的。 我希望对远程URL块的调用直到出现一些答案为止 ,就像在Ajax中一样,但是没有异步部分,或者我要说要进行JAX调用。 是否有任何技术可以使以下事情发生(使用JQuery)(…使用JQuery或其他解决方案): 我只是想知道-想学习。 实际上,有时会阻塞直到回复合适为止。我并不是说要浏览器阻止,而只是脚本运行时。 问题答案: 您可以在使用jQuery

  • 我读过很多关于这方面的文章,但也有2012年或更早的文章。 (我只是打算从数据库中读取和插入一些数据。)

  • 有没有办法阻止用户留下一个片段(点击后退按钮,从导航中导航到其他片段,等等)? 情况是,当用户点击将文件备份到USB设备时,备份过程开始(线程),如果他留下这个片段,备份过程会发生一些尴尬的事情,应用程序会崩溃。 我在想我是否可以使用一些生命周期回调,比如: 或 有没有其他方法来处理这种情况并提供最好的用户体验(可能是一些对话片段)?

  • 由于不推荐使用TabActivity,我需要找到一种方法来使用片段。在我知道它如何工作之前,我已经使用了碎片,但我需要一个指南来创建我的标签主机与碎片活动。我在互联网上找到了几个例子,它们都是关于将片段放入标签的容器中的。

  • 我们使用的是片段,我们不需要在重新创建活动时自动恢复它们。但是,Android每次调用->时,都会恢复片段,即使我们对这些片段使用setRetaInstance(false)。 附言。我们知道,在为配置更改重新创建活动的情况下,可以通过在manifest中添加来完成。但是,在自动清理内存的情况下,如何重新创建活动呢?