【问题标题】:The Fragment refreshes on back- Android NavigationFragment 背面刷新 - Android Navigation
【发布时间】:2019-07-26 06:16:45
【问题描述】:

我正在使用 Android Navigation 组件制作应用程序。但是我遇到了一个非常基本的问题,这可能会导致我的应用程序的整个开发出现问题。

情景

我有这个片段,在 onViewCreated 我正在观察我的视图模型中的一个字段。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    viewModel = ViewModelProviders.of(this).get(EventDetailsViewModel::class.java)
    viewModel.init(context!!,eventId)

    viewModel.onEventDetailsUpdated().observe(this, Observer {
        setEventDetails(it)
    })

}

setEventDetails 方法中,我用数据设置了recyclerviews。

问题

这个片段是一个带有卷轴的长片段。假设我向下滚动很长一段距离,然后单击一个按钮,将我带到另一个片段。

但是当我回到这个片段时,它再次将我带到顶部并执行它在第一次加载时所做的一切。 这可能令人不安。这有点像重新创建整个片段,而不是保持其旧状态。

我尝试了什么

我搜索了很多问题。并经历了This Github QueryThis SO questionAnother Git...但我无法解决我的问题。

请帮忙,在此先感谢。

【问题讨论】:

  • 你正在替换片段或只是添加
  • 天真的解决方案:尝试在暂停时将当前 scollY 保存在 viewmodel 中并滚动到 onResume 中保存的 scrollY
  • @NehaRathore 我正在使用android的jetpack导航组件,所以我正在调用findNavController().navigate方法。我没有使用片段管理器
  • @TheBat 你有解决方案吗?我也遇到了同样的问题,我也在使用 NavController。

标签: android android-fragments android-jetpack android-architecture-navigation android-jetpack-navigation


【解决方案1】:

是的,只要您向前导航到另一个片段,片段的视图就会被破坏。

RecyclerView 的滚动位置应该会自动恢复,即使创建了新的 RecyclerView 实例并设置了新的 Adapter 实例,只要您使用与以前相同的数据集设置所有内容。此外,您需要在第一次布局传递之前完成。

这意味着您需要旧数据并且需要立即准备好(没有异步加载!)。 ViewModelProvider 应该返回相同的 ViewModel 实例。该 ViewModel 包含您应该能够同步获取并在 UI 上显示的数据。确保重构您的 viewModel.init 方法 - 如果数据已经存在,您不想进行 API 调用以防万一。一个简单的布尔值isInitialized 可以在这里工作,或者您甚至可以检查 LiveData 是否为空。

此外,在 LiveData 上调用 observe 时,您会遇到一个微妙的错误。 onViewCreated 可以为同一个片段调用多次(每次你向前和向后导航时!) - 所以每次都会调用observe。您的 Fragment 将多次订阅同一个 LiveData。这意味着您将多次获得事件(每个订阅一次)。这也可能导致 RecyclerView 状态恢复出现问题。您的订阅与您传递的生命周期所有者相关联。您传递了与 Fragment 生命周期相关联的 Fragment 生命周期所有者。您要做的是传递 Fragment 视图的生命周期所有者,因此,每当视图被销毁时,订阅就会被清除,并且您只有 1 个订阅,并且只有在 Fragment 的视图处于活动状态时。为此,您可以使用getViewLifecycleOwner 而不是this

【讨论】:

    【解决方案2】:

    您需要依赖 ViewModel 来恢复片段状态,因为 ViewModel 不会在片段更改时被破坏。 在您的 viewModel 中,创建一个变量 listState

    class HomeViewModel : ViewModel() {
        var listState: Parcelable? = null
    }
    

    然后在你的片段中使用下面的代码

    
    class HomeFragment : Fragment() {
        private val viewModel by navGraphViewModels<HomeViewModel>(R.id.mobile_navigation)
    
        override fun onActivityCreated(savedInstanceState: Bundle?) {
            super.onActivityCreated(savedInstanceState)
    
            if (viewModel.listState != null) {
                list.layoutManager?.onRestoreInstanceState(viewModel.listState)
                viewModel.listState = null
            }else{
               //load data normally
        }
    
        override fun onDestroyView() {
            super.onDestroyView()
            viewModel.listState = list.layoutManager?.onSaveInstanceState()
        }
    }
    

    【讨论】:

    • 我可以在 java 中获得相同的代码吗?我遇到了同样的问题,我找到的每个解决方案都在 kotlin 中。
    • 当我调用 viewModel.listState = list.layoutManager?.onSaveInstanceState() 时,列表变量为 null,因为 onSaveInstanceState() 返回 null
    【解决方案3】:

    您不必每次都初始化视图模型。只需在初始化之前检查 null 。不知道kotlin,还是会是这样的:

    if(viewModel == null){
        viewModel = ViewModelProviders.of(this).get(EventDetailsViewModel::class.java)
        viewModel.init(context!!,eventId)
    }
    

    【讨论】:

      【解决方案4】:

      尝试将此代码放在您第一次调用片段的位置。

      ft = fm.beginTransaction();
       ft.replace(R.id.main_fragment, yourSearchFragment, "searchFragment");
       ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
       ft.commit();
      

      回到片段时这个

      ft = fm.beginTransaction();
       ft.hide(getFragmentManager().findFragmentByTag("searchFragment"));
       ft.add(R.id.main_fragment, yourDetailfragment);
       ft.addToBackStack(null);
       ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
       ft.commit();
      

      【讨论】:

      • 我正在使用android的jetpack导航组件,所以我正在调用findNavController().navigate方法。我没有使用片段管理器
      猜你喜欢
      • 2014-03-20
      • 1970-01-01
      • 2017-02-05
      • 1970-01-01
      • 1970-01-01
      • 2021-06-04
      • 1970-01-01
      • 1970-01-01
      • 2019-05-28
      相关资源
      最近更新 更多