Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >带有片段和Jetpack导航的Viewpager2 :恢复片段而不是重新创建它们

带有片段和Jetpack导航的Viewpager2 :恢复片段而不是重新创建它们
EN

Stack Overflow用户
提问于 2019-07-30 12:21:43
回答 4查看 4.8K关注 0票数 41

我在Fragment中有一个Viewpager2 (让我们称它为HomeFragment)。该Viewpager本身也包含Fragments。当我离开HomeFragment时,它的视图将被销毁,当我导航回来时,该视图将被重新创建。现在,我在onViewCreated()期间在HomeFragment中设置了Viewpager2的适配器。因此,当我导航回HomeFragment时,将重新创建适配器,这也会重新创建Viewpager2中的所有Fragments,并且当前项将重置为0。如果我尝试重用在第一次创建HomeFragment时实例化的适配器,则会得到一个异常,因为在FragmentStateAdapter中进行了此检查

代码语言:javascript
运行
AI代码解释
复制
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        checkArgument(mFragmentMaxLifecycleEnforcer == null);

有人知道如何防止在返回时重新创建所有内容吗?否则,这是一个相当大的性能开销,并阻碍我的用户体验。

EN

回答 4

Stack Overflow用户

发布于 2020-10-30 15:04:41

我在这方面花了一些时间,我已经为任何需要听到它的人诊断了这个问题。我试着让我的解决方案尽可能的传统。如果我们看一下你的声明:

因此,当我导航回HomeFragment时,适配器将被重新创建,这也将重新创建Viewpager2中的所有片段,并且当前项被重置为0。

问题是当前项被重置为0,因为重新创建了适配器所基于的列表。要解决这个问题,我们不需要保存适配器,只需要保存其中的数据。考虑到这一点,解决问题一点也不难。

让我们来布置一些定义:

正如你所说,

  • HomeFragment是你的ViewPager2的主机,
  • MainActivity是运行的活动,它托管了HomeFragment和它里面所有创建的片段,
  • ,我们正在分页浏览MyFragment的实例。您甚至可以通过多种类型的片段进行分页,但这超出了您的ViewPager2.

的适配器FragmentStateAdapter的范围,这超出了example.

  • PagerAdapter的范围

在本例中,MyFragment具有构造函数constructor(id : Int)。然后,PagerAdapter可能会出现如下所示:

代码语言:javascript
运行
AI代码解释
复制
class PagerAdapter(fm : Fragment) : FragmentStateAdapter(fm){
    
    var ids : List<Int> = listOf()

    ...
    
    override fun createFragment(position : Int) : Fragment{
        return MyFragment(ids[position])
    }
    

}

我们面临的问题是,每次重新创建PagerAdapter时,构造函数都会被调用,正如我们在上面看到的那样,该构造函数会将ids设置为一个空列表。

我的第一个想法是,也许我可以把fm换成MainActivity。我不会离开MainActivity,所以我不知道为什么,但是这个解决方案不起作用。

相反,您需要做的是从PagerAdapter中提取数据。创建一个"viewModel":

代码语言:javascript
运行
AI代码解释
复制
    /* We do NOT extend ViewModel. This naming just indicates that this is your data- 
    storage vehicle for PagerAdapter*/
    data class PagerAdapterViewModel(
    var ids : List<Int> 
    )

然后,在PagerAdapter中进行以下调整:

代码语言:javascript
运行
AI代码解释
复制
class PagerAdapter(
    fm : Fragment,
    private val viewModel : PagerAdapterViewModel 
) : FragmentStateAdapter(fm){
    
    // by creating custom getters and setters, you are migrating your code to this 
    // implementation without needing to adjust any code outside of the adapter 
    var ids : List<Int>
        get() = viewModel.ids 
        set(value) {viewModel.ids = value} 
    
    override fun createFragment(position : Int) : Fragment{
        return MyFragment(ids[position])
    }
    

}

最后,在HomeFragment中,您将拥有如下内容:

代码语言:javascript
运行
AI代码解释
复制
class HomeFragment : Fragment(){ 

    ... 

    /** Calling "by lazy" ensures that this object is only created once, and hence
    we retain the data stored in it, even when navigating away. */
    private val pagerAdapterViewModel : PagerAdapterViewModel by lazy{
        PagerAdapterViewModel(listOf())
    }

    private lateinit var pagerAdapter : PagerAdapter

    ...

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        ...
        pagerAdapter = PagerAdapter(this, pagerAdapterViewModel)
        pager.adapter = pagerAdapter 
        ...
    }
    
    ...

}
票数 2
EN

Stack Overflow用户

发布于 2020-12-28 12:44:58

您可以将ViewPager的初始页面作为NavHostFragment,这些页面有自己的后端堆栈,这将导致在下面的gif中实现

为每个选项卡创建一个NavHost片段,也可以有一个通用的选项卡来添加它

代码语言:javascript
运行
AI代码解释
复制
/**
 * Using [FragmentStateAdapter.registerFragmentTransactionCallback] with [FragmentStateAdapter] solves back navigation instead of using [OnBackPressedCallback.handleOnBackPressed] in every [NavHostFragment]
 * ### Should set app:defaultNavHost="true" for [NavHostFragment] for this to work
 */
class DashboardNavHostFragment : BaseDataBindingFragment<FragmentNavhostDashboardBinding>() {
    override fun getLayoutRes(): Int = R.layout.fragment_navhost_dashboard

    private var navController: NavController? = null

    private val nestedNavHostFragmentId = R.id.nested_nav_host_fragment_dashboard


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

        val nestedNavHostFragment =
            childFragmentManager.findFragmentById(nestedNavHostFragmentId) as? NavHostFragment
        navController = nestedNavHostFragment?.navController

    }

}

此片段的布局

代码语言:javascript
运行
AI代码解释
复制
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:layout_constraintEnd_toEndOf="parent"
            android:background="#0D47A1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/ThemeOverlay.AppCompat.ActionBar" />

        </com.google.android.material.appbar.AppBarLayout>

        <fragment
            android:id="@+id/nested_nav_host_fragment_dashboard"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/appbar"

            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_graph_dashboard"/>

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

并为仪表板的每个页面创建一个导航图,正如您在上面看到的,我们需要nav_graph_dashboard.

此页的图形为

代码语言:javascript
运行
AI代码解释
复制
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph_dashboard"
    app:startDestination="@id/dashboardFragment1">


    <fragment
        android:id="@+id/dashboardFragment1"
        android:name="com.smarttoolfactory.tutorial6_4_navigationui_viewpager_fragmenttoolbar_nested_navigation.blankfragment.DashboardFragment1"
        android:label="DashboardFragment1"
        tools:layout="@layout/fragment_dashboard1">
        <action
            android:id="@+id/action_dashboardFragment1_to_dashboardFragment2"
            app:destination="@id/dashboardFragment2" />
    </fragment>

    <fragment
        android:id="@+id/dashboardFragment2"
        android:name="com.smarttoolfactory.tutorial6_4_navigationui_viewpager_fragmenttoolbar_nested_navigation.blankfragment.DashboardFragment2"
        android:label="DashboardFragment2"
        tools:layout="@layout/fragment_dashboard2">
        <action
            android:id="@+id/action_dashboardFragment2_to_dashboardFragment3"
            app:destination="@id/dashboardFragment3" />
    </fragment>
    <fragment
        android:id="@+id/dashboardFragment3"
        android:name="com.smarttoolfactory.tutorial6_4_navigationui_viewpager_fragmenttoolbar_nested_navigation.blankfragment.DashboardFragment3"
        android:label="DashboardFragment3"
        tools:layout="@layout/fragment_dashboard3" >
        <action
            android:id="@+id/action_dashboardFragment3_to_dashboardFragment1"
            app:destination="@id/dashboardFragment1"
            app:popUpTo="@id/dashboardFragment1"
            app:popUpToInclusive="true" />
    </fragment>

</navigation>

让我们将这些NavHostFragments与FragmentStateAdapter合并,并实现默认情况下不起作用的back press导航。

代码语言:javascript
运行
AI代码解释
复制
/**
 * FragmentStateAdapter to contain ViewPager2 fragments inside another fragment.
 *
 * *  Create FragmentStateAdapter with viewLifeCycleOwner instead of Fragment to make sure
 * that it lives between [Fragment.onCreateView] and [Fragment.onDestroyView] while [View] is alive
 *
 * * https://stackoverflow.com/questions/61779776/leak-canary-detects-memory-leaks-for-tablayout-with-viewpager2
 */
class ChildFragmentStateAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
    FragmentStateAdapter(fragmentManager, lifecycle) {

    init {
        // Add a FragmentTransactionCallback to handle changing
        // the primary navigation fragment
        registerFragmentTransactionCallback(object : FragmentTransactionCallback() {
            override fun onFragmentMaxLifecyclePreUpdated(
                fragment: Fragment,
                maxLifecycleState: Lifecycle.State
            ) = if (maxLifecycleState == Lifecycle.State.RESUMED) {

                // This fragment is becoming the active Fragment - set it to
                // the primary navigation fragment in the OnPostEventListener
                OnPostEventListener {
                    fragment.parentFragmentManager.commitNow {
                        setPrimaryNavigationFragment(fragment)
                    }
                }

            } else {
                super.onFragmentMaxLifecyclePreUpdated(fragment, maxLifecycleState)
            }
        })
    }


    override fun getItemCount(): Int = 3

    override fun createFragment(position: Int): Fragment {

        return when (position) {
            0 -> HomeNavHostFragment()
            1 -> DashboardNavHostFragment()
            else -> NotificationHostFragment()
        }
    }

}

您还需要注意内存泄漏,因此如果您的ViewPager2本身在Fragment中,请使用viewLifecycleOwner而不是lifeycleOwner

您可以在此tutorial link中查看其他示例和更多内容。

票数 1
EN

Stack Overflow用户

发布于 2021-04-02 07:40:38

我试着设置

代码语言:javascript
运行
AI代码解释
复制
viewPager2.setOffscreenPageLimit(ViewPager2.OFFSCREEN PAGE LIMIT_DEFAULT);

在那之后,碎片的行为变得正常。

有关OffscreenPageLimit here的更多信息

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57271553

复制
相关文章
在Java中使用Highcharts+Ajax+Json生成动态饼图
1.由于HighCharts运行于JQuery,所以需要引入jQuery。 jquery-1.8.3.min HighCharts核心js文件 highcharts.js 导出功能需要引入的js exporting.js 完整文件 Highcharts-4.2.5 2.在jsp页面引入如上文件
geekfly
2022/05/06
1.1K0
在Java中使用Highcharts+Ajax+Json生成动态饼图
Highcharts-11-饼图绘制大全
本文中介绍的是如何利用python-highcharts绘制各种饼图来满足不同的需求,主要包含:
皮大大
2021/03/08
1.5K0
Highcharts-9-双饼图绘制
Highcharts-9-双饼图制作 本文中只介绍一种和饼图相关的图形:双饼图 双饼图 效果 代码 # -*- coding: utf-8 -*- """ 说明:制作双饼图 作者:Peter """
皮大大
2021/03/07
1.2K0
Highcharts-8-基础饼图绘制
本文中介绍的是如何在jupyter notebook中通过python-highcharts绘制常见的饼图:
皮大大
2021/03/07
1.9K0
Highcharts-10-饼图颜色设置
实现上面的效果主要是通过'color': 'Highcharts.getOptions().colors[0]方法。当colors[i]中的i取相同的值,则颜色会相同。
皮大大
2021/03/07
2.6K0
用 Highcharts 绘制饼图,也很强大
前不久,阳哥在「Python数据之道」分享了读者投稿的文章,较为综合的介绍了可视化库 Highcharts ,这个一个 JavaScript 下的可视化工具,同时也有 Python 版本。前文链接如下:
周萝卜
2021/04/02
1.5K0
用 Highcharts 绘制饼图,也很强大
肝!用 Highcharts 绘制饼图,也很强大
前不久,分享了读者投稿的文章,较为综合的介绍了可视化库 Highcharts ,这个一个 JavaScript 下的可视化工具,同时也有 Python 版本。
小小詹同学
2021/04/19
2K0
肝!用 Highcharts 绘制饼图,也很强大
echarts饼图中间文字,固定,改成自己想要的值
(仅供自己参考) 中间是可以放两行文字的,一行是自己计算的比例,还可以放一个如:(这里就不多描述了上面的文字是在titletop中设置的可以看看echarts API的配置项)
全栈程序员站长
2022/11/03
4.8K0
PowerBI 工具提示 在图上显示图
很多人会好奇的是,这个页面如何随着其他的图而变呢?其道理在于它会受到其他图的筛选。
BI佐罗
2020/08/20
2.3K0
免费的图表工具
Ajax MGraph 基于 Prototype.js 的 Ajax 图表库,纯 XHTML 和 CSS 实现。
DougWang
2020/02/18
1.6K0
【原创】说好的暴雨呢,搁哪呢?还能不能 雨~露~均~沾?
不是说下大雨吗?玩儿呐?搁哪呢?大雨搁哪呢?下丢啦?哗啦到海里去啦?让五娃给吞啦?南方整的那老大,看不起副中心咋的?还能不能 雨~露~均~沾~?你说我小船儿都买好了,搁哪划,搁哪划!!给我一个完美的解释! 北京气象局通知: 原约定于昨天和今早来的暴雨,因办进京证,耽误了点儿时间,或许今天夜间赶到。这场雨如果下大了肯定不小,如果下小了也肯定不会大,请市民再耐心等待!具体情况等下完后气象台会报给市民。气象台温馨提醒:今天如果不下雨,明天不下雨的话,这两天就没有雨了,就看后天的了。 气象台郑重劝告
码神联盟
2018/04/02
2.8K0
【原创】说好的暴雨呢,搁哪呢?还能不能 雨~露~均~沾?
如何在 Highcharts 图中当所占百分比为 0 时不显示0%
图片.png 解决办法其实很简单,将enabled属性改为false即可: dataLabels: { enabled: false } 图片.png 完成之后的显示如下 图片.png
王小婷
2018/09/26
1.1K0
Hadoop数据分析平台实战——190Highcharts介绍离线数据分析平台实战——190Highcharts介绍
离线数据分析平台实战——190Highcharts介绍 Highcharts介绍 Highcharts 是Highsoft提供的一个用纯JavaScript编写的一个图表库, 能够很简单便捷的在web网站或是web应用程序添加有交互性的图表,并且免费提供给个人学习、个人网站和非商业用途使用。 HighCharts支持的图表类型有曲线图、区域图、柱状图、饼状图、散状点图和综合图表等。 Highcharts特点:兼容性强、图表的主题类型多、操作性强、使用简单。 除了Highcharts以外,Highsof
Albert陈凯
2018/04/08
1.4K0
在 SwiftUI 视图中打开 URL 的若干方法
本文将介绍在 SwiftUI 视图中打开 URL 的若干种方式,其他的内容还包括如何自动识别文本中的内容并为其转换为可点击链接,以及如何自定义打开 URL 前后的行为等。
东坡肘子
2022/07/28
7.9K1
在 SwiftUI 视图中打开 URL 的若干方法
盘点10款超好用的数据可视化工具
现代社会早已进入读图时代,图像在一定上程度上取代了文字,占据了主导地位。对于数据分析来说,一张清晰的可视化图表确实比纷繁复杂的数字更清晰美观。随着科技的发展以及可视化需求的急剧增大,涌现了大批的数据可视化工具,通过对比分析市面上众多的数据可视化工具之后,我们挑选了几款给大家进行参考。
数据前沿
2020/08/26
7.3K0
盘点10款超好用的数据可视化工具
在图中添加多边形
在matplotlib中有一个子模块patches, 提供了绘制各种多边形的功能,常用的多边形及其画法如下
生信修炼手册
2020/09/23
6470
在图中添加多边形
微信小程序1
小程序组件化开发框架 https://tencent.github.io/wepy/
达达前端
2019/07/03
2.2K0
微信小程序1
商业图表工具推荐,热门商业图表工具有哪些?
在如今的商业环境下,数据分析和可视化是非常重要的一环。不仅可以帮助企业更好地了解自身情况,还能为决策提供有力支持。因此,选择一个好用的商业图表工具对于报表开发人员来说是非常重要的。下面将为大家介绍7款热门商业图表工具,其中第一个是VeryReport商业图表工具。
报表专家
2023/06/08
4180
推荐12个最好的 JavaScript 图形绘制库
 众多周知,图形和图表要比文本更具表现力和说服力。图表是数据图形化的表示,通过形象的图表来展示数据,比如条形图,折线图,饼图等等。可视化图表可以帮助开发者更容易理解复杂的数据,提高生产的效率和 Web 应用和项目的可靠性。
用户3055976
2018/09/12
7.8K0
推荐12个最好的 JavaScript 图形绘制库
点击加载更多

相似问题

在Highcharts工具提示中定位饼图

12

Highcharts饼图-工具提示中的链接

10

如何使highcharts工具提示显示在饼图之外?

12

%未显示在工具提示饼图highcharts js中

06

HighCharts列图中的工具提示帮助

22
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档