Android 碎片。getViewLifeCycleOwner没有';t防止多次调用LiveData Observer

Android 碎片。getViewLifeCycleOwner没有';t防止多次调用LiveData Observer,android,kotlin,android-fragments,navigation,android-livedata,Android,Kotlin,Android Fragments,Navigation,Android Livedata,我使用干净的体系结构、LiveData、导航组件和底部导航视图。 我正在创建一个带有三个选项卡的简单应用程序。默认情况下,第一个选项卡片段使用一些API加载用户数据。当我转到另一个选项卡,然后返回到第一个选项卡片段时,我看到,observe返回一个新数据 我需要观察在切换回第一个选项卡时不再返回数据!我做错了什么?你能帮我吗 注意:对于导航,我使用切换选项卡前后的示例onDestroy未被调用 第一个解决方案在文章中说: 一个合适的解决方案是使用getViewLifeCycleOwner()作为

我使用干净的体系结构、LiveData、导航组件和底部导航视图。
我正在创建一个带有三个选项卡的简单应用程序。默认情况下,第一个选项卡片段使用一些API加载用户数据。当我转到另一个选项卡,然后返回到第一个选项卡片段时,我看到,
observe
返回一个新数据

我需要
观察
在切换回第一个选项卡时不再返回数据!我做错了什么?你能帮我吗

注意:对于导航,我使用切换选项卡前后的示例
onDestroy
未被调用

第一个解决方案在文章中说:

一个合适的解决方案是使用getViewLifeCycleOwner()作为生命周期电源,同时观察ActivityCreated中的LiveData,如下所示

我使用以下代码,但它不适用于我:

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    Timber.d("onActivityCreated")
    viewModel.getProfileLive().observe(viewLifecycleOwner, observer)
}
文章中的第二个解决方案建议在onDestroyView()中使用重置现有观察者并手动取消订阅观察者。但这对我也不起作用

ProfileFragment.kt

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()
    }
}
class ProfileUseCase@Inject构造函数(
private val profileRepository:profileRepository
) {
fun getProfile():LiveData{
返回profileRepository.getProfile()
}
}
ProfileRepository.kt。 类ProfileRepository@Inject构造函数( 私人val loginUserDao:loginUserDao, private val profileDao:profileDao, ){

fun getProfile():LiveData=
liveData(Dispatchers.IO)
{
发出(Resource.loading(数据=null))
val profile=profileDao.getProfile()
//发射成功结果。。。
}

}这是因为片段生命周期的工作方式。当您从片段来回移动时,会再次调用
onViewCreated()
。在
onViewCreated
中,您正在调用
viewModel.getProfileLive()
,它将livedata从存储库返回到观察到它

由于每次返回到片段时都会调用
onViewCreated()
,因此对
viewModel.getProfileLive()
的调用也是如此,而存储库也会再次被调用,从而再次触发片段中的
observe
方法

为了解决这个问题,, 在您的视图模型中创建一个LiveData变量,将其设置为从存储库中返回的LiveData。 在片段中观察视图模型的LiveData变量,而不是从存储库返回的变量
这样,您的
observe
方法将在第一次触发,并且仅当存储库中的数据的值发生更改时才会触发。

LiveData始终缓存最后的结果并重新交付,这与您的观察者的生命周期无关(使用
getViewLifecycleOwner()
时已经正确)。@ianhanniballake以及解决此问题的正确方法是什么?“我明白了,该观察返回一个新数据”这到底有什么问题?“我需要观察不再返回数据”为什么?@Tobi让我们假设你在使用Instagram。每次切换选项卡时,都会发出一个新的请求来加载提要和其他项目。在我的简单应用程序中,导航应该以类似的方式工作。如果我理解正确,你希望在切换选项卡时再次调用API,对吗?长话短说:在构造函数中加载数据如果你的viewmodel没有出现在你的长篇故事片段中,这样他就可以理解错在哪里了。当然,有时用一句话来总结它,以避免潜在的混乱;)谢谢!如果我需要更新数据,在这种情况下,正确的方法是什么?
fun getProfile(): LiveData<Resource<Profile>> =
    liveData(Dispatchers.IO)
    {
        emit(Resource.loading(data = null))

        val profile = profileDao.getProfile()

        // Emit Success result...
    }