【问题标题】:How to avoid multiple instances of fragments in Activity after app is killed and resumed?如何避免应用被杀死并恢复后Activity中的多个片段实例?
【发布时间】:2015-05-16 16:12:01
【问题描述】:

我有一个应用程序,其主屏幕有 2 个片段(目前)和一个导航抽屉。目前我在启动时加载片段 A(探索)并在单击时加载片段 B。从那时起,我展示和隐藏片段。它比每次点击都重新创建片段要快,而且我的片段 A 需要一些时间来加载。

我注意到,当我转到片段 B 并从那里转到另一个活动(我们称之为活动 2)并离开应用程序并等待它被杀死(或做一些疯狂的事情,比如更改设备语言) ,然后回到相同的活动,它仍然存在。当我按返回返回片段 B 时,有时(50% 的时间)片段 B 被绘制在片段 A 上。单击抽屉中的片段 A 时,片段 A 看起来很好,但单击片段 B 时,还有另一个实例片段 A 和片段 B 的顶部。

我在这个问题上花了超过 2 天的时间,却一无所获。

这是我选择片段的代码:

private void selectItem(int position, boolean addExploreFragment) {
    Log.d(tag, "selectItem: " + position);

    FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
    fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);

    //add explore fragment - this is called on app startup, but also when the app is killed and resumed which results in 2 explore fragments

    if (addExploreFragment){

        fragmentTransaction.replace(R.id.content_frame, mExploreFragment, EXPLORE_FRAGMENT_TAG);
        Log.d(tag, "Replaced frame and added "+ mFragmentTags[position]);

    } else {
        //add fragment for the first time
        if (getSupportFragmentManager().findFragmentByTag(mFragmentTags[position]) == null && position != 0) {
            fragmentTransaction.add(R.id.content_frame, mFragments[position], mFragmentTags[position]);
            Log.d(tag, "Added Fragment: "+ mFragmentTags[position]);
        }
        //shows and hides fragments
        for (int i = 0; i < mFragments.length; i++) {
            if (i == position) {
                fragmentTransaction.show(mFragments[i]);
                Log.d(tag, "Showing Fragment: "+ mFragmentTags[i]);
            } else {
                if (getSupportFragmentManager().findFragmentByTag(mFragmentTags[i]) != null) {
                    fragmentTransaction.hide(mFragments[i]);
                    Log.d(tag, "Hid Fragment: "+ mFragmentTags[i]);
                }
            }
        }

    }

    fragmentTransaction.commit();
    //not null check for calling selectItem(0) before loading the drawer
    if (mDrawerList != null){
        mDrawerList.setItemChecked(position, true);
    }
}

我确定,探索片段被创建了两次,并且这两个实例的行为彼此独立(只是共享)。

我不知道下一步该做什么。这是一个在低端设备上很容易重现的问题,但在像 Nexus 4(我的测试设备)这样的设备上,可以通过更改设备语言来重现该问题。

有人对此有任何想法吗?基本上,如果 addExploreFragment 块在已经存在 exploreFragment 时没有被调用,我认为这个问题可以解决,但我一直无法这样做。此外,我尝试删除所有片段,然后添加 exploreFragment 但同样的事情发生(50% 的时间)。

谢谢!很抱歉这篇长文,我觉得我应该分享所有细节。

更新:当我更改设备语言并返回 Activity 2 上的应用程序并返回 Home Activity 时,它打开了片段 B,这很好,但片段 A 被重新创建,因为这是一个沉重的碎片,系统可能会将其从内存中删除。同样,如果系统将其删除,则可以重新创建它,但是为什么在未删除它时会重新创建它。我相信这与我的代码有关,每次第二次尝试(不关闭应用程序)都会发生这种情况,重片段 A 的 2 个实例。没有想法。

但是不应该fragmentTransaction.replace 删除所有之前添加的片段,然后添加exploreFragment。它不是那样工作的。片段 A 和片段 B 都没有被删除。

【问题讨论】:

  • 是的,但是您仍然错过了一些细节,Fragment A 是如何声明的?静态方式?也就是说,它是按名称在 xml 中声明的吗?如果是,您创建了两个实例。还有你在哪里切换addExploreFragment?。
  • @Elltz 不,所有片段都是动态创建并添加到框架布局中的。 addExploreFragment 仅在应用启动时为真。在其他任何地方,调用 selectItem 时都设置为 false。所以基本上,当添加探索片段时。这是一个多余的参数,现在我想起来了。
  • 如果我理解正确,在 MainActivity 中调用了 selectItem()。在生命周期的上下文中,它调用了哪些覆盖方法?我一直盯着代码,这是我看到的唯一问题。
  • @TheOriginalAndroid 它在 onCreate 上调用,addExploreFragment 设置为 true。除此之外,在 DrawerItemClickListener 中的 onItemClick 中调用来切换 Fragment,addExploreFragment 设置为 false。
  • 我同意您在 onCreate 中的代码。我确实发布了答案。

标签: android android-fragments fragmenttransaction


【解决方案1】:

我发现了一些对我来说很奇怪的新东西。当您使用fragmentTransaction.add 时,您拥有的侦听器,如上一个片段 上的DrawerItemClickListener,仍然处于活动状态。即使您使用fragmentTransaction.commit,也是如此。

所以...我怀疑当使用 add 方法时,您实际上单击了另一个隐藏按钮或隐藏的 UI,该按钮在前一个片段上具有事件侦听器。我当然不喜欢这样,效果可能会很混乱。是的,这发生在我身上,我有一段时间不明白为什么。

目前,我认为最简单的代码修复方法是使用 replace 方法而不是 add。 replace() 使侦听器处于非活动状态。如果它有效,那么您可以做出更好/优雅的修复。

让我知道会发生什么......

【讨论】:

  • 监听器被附加到活动中,所以如果你看到这种行为,那真的很奇怪。您是否尝试过启用片段管理器的日志记录。它给了我一些见解,证实了一些疑问并创造了更多,但还没有解决方案。我现在不能使用替换,因为探索片段需要时间来加载。我正在考虑解决这个问题并使用替换。但这可能需要对应用程序进行一些更新。感谢您的所有帮助。
【解决方案2】:

我开始注意到你的帖子

当我去片段 B 去另一个活动时

当您交互或启动另一个 Activity 时,您会启动一组新的 Fragment。看看这个谷歌网页@Fragments Lifecycle。 为了澄清我的主张,有一句话说

片段必须始终嵌入到活动中,并且片段的 生命周期直接受宿主活动生命周期的影响。

你不妨至少读几段。

我不确定您的解决方案应该是什么。也许让片段在你拥有的两个活动之间变得与众不同、不同和清晰。

【讨论】:

  • 感谢您的帖子,但这并不能解释为什么片段 A 会在应用程序被终止时重新创建 50% 的时间(编辑帖子以包含“50% 的时间”)。片段 A 和 B 在一个活动中(我们称之为活动 1)和来自片段 B,当我转到另一个活动(活动 2)然后按手机上的主页按钮以暂停应用程序并更改手机区域设置并来回到活动 2,然后回到包含 2 个片段的活动 1,我在帖子中提到的事情发生了。如果我错过了你的观点,请告诉我。
猜你喜欢
  • 1970-01-01
  • 2013-04-17
  • 2013-08-05
  • 1970-01-01
  • 2014-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多