防止 Android 中的片段恢复

问题描述 投票:0回答:10

我们使用的是Fragments,我们不需要它们在重新创建Activity时自动恢复。 但是每次调用

Activity::onCreate(Bundle savedInstanceState)
->
super.onCreate(savedInstanceState)
时,Android 都会恢复 Fragment,即使我们对这些 Fragment 使用 setRetainInstance(false) 。

而且,在那些

Fragments
Fragment.performCreateView()
中,直接调用而不经过
Fragment::onAttach()
等等。另外,恢复后的某些字段为空
Fragment
...

有人知道如何防止Android恢复碎片吗?

附注我们知道,如果要为配置更改重新创建 Activity,可以通过添加到清单 a

ndroid:configChanges="orientation|screenSize|screenLayout
来完成。但是在自动内存清理的情况下重新创建活动怎么样?

android memory-management garbage-collection fragment recreate
10个回答
59
投票

我们通过添加活动来完成:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(null);
}

它会抑制活动创建/重新创建周期中保存的任何数据,并避免片段自动重新创建。


24
投票

@goRGon 的答案对我来说非常有用,但是当您需要在重新创建后转发到您的活动时有更多信息时,这种使用会导致严重的问题。

这是改进版本,仅删除“碎片”,但保留所有其他参数。

从捆绑包中删除的

ID 是

android.support.v4.app.FragmentActivity
类的一部分,作为
FRAGMENTS_TAG
字段。当然,它可能会随着时间的推移而改变,但这不是预期的。

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(createBundleNoFragmentRestore(savedInstanceState));
}

/**
 * Improve bundle to prevent restoring of fragments.
 * @param bundle bundle container
 * @return improved bundle with removed "fragments parcelable"
 */
private static Bundle createBundleNoFragmentRestore(Bundle bundle) {
    if (bundle != null) {
        bundle.remove("android:support:fragments");
    }
    return bundle;
}

4
投票

我遇到了

TransactionTooLargeException
的问题。值得庆幸的是,在使用 tolargetool 后,我发现片段(android:support:fragments)一直在内存中,并且事务变得太大。所以最后我做到了,效果很好。

@Override
public void onSaveInstanceState(final Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putSerializable("android:support:fragments", null);
}

编辑:我将其添加到活动中。就我而言,我有一个 Activity 应用程序和多个片段。


3
投票

那些在使用已接受答案中描述的方法时使用 ViewPager 获得 NPE 的人,请覆盖

ViewPager.onRestoreInstanceState(Parcelable state)

方法及调用

super.onRestoreInstanceState(null);

相反。


1
投票

我删除了Activity的onCreate中的碎片。


0
投票

对于带有

ViewPager
的应用程序,我会在创建之前删除
onCreate()
中的片段。

基于此线程:从容器中删除所有碎片,我们有:

FragmentManager fm = getSupportFragmentManager();
for (Fragment fragment: fm.getFragments()) {
  fm.beginTransaction().remove(fragment).commitNow();
}

0
投票

将此用于 androidx

override fun onCreate(savedInstanceState: Bundle?) {
   preventFragmentRecreation()
   super.onCreate(savedInstanceState) 
}

private fun preventFragmentRecreation() {
   supportFragmentManager.addFragmentOnAttachListener { _, _ ->
            savedStateRegistry.unregisterSavedStateProvider("android:support:fragments")
        }
}

0
投票

这对我有用

@Override
public void onSaveInstanceState(final Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.remove("androidx.lifecycle.BundlableSavedStateRegistry.key");
}
    

0
投票

如上所述,

androidx:support:fragments
位于AndroidX上的
androidx.lifecycle.BundlableSavedStateRegistry.key
下,要从捆绑包中完全删除片段,您可以清理捆绑包和嵌套捆绑包:

  override fun onCreate(savedInstanceState: Bundle?) {
    SplashScreen.show(this)

    /**
     * Remove fragments from saved state to prevent crashes
     */
    if (savedInstanceState != null) {
      savedInstanceState.remove("android:support:fragments")
      savedInstanceState.remove("android:fragments")

      val bundlableSavedStateRegistry = savedInstanceState.getBundle("androidx.lifecycle.BundlableSavedStateRegistry.key");
      bundlableSavedStateRegistry?.remove("android:support:fragments")

      savedInstanceState.putBundle("androidx.lifecycle.BundlableSavedStateRegistry.key", bundlableSavedStateRegistry)
    }


    super.onCreate(savedInstanceState)

此修复了https://github.com/software-mansion/react-native-screens/issues/17

React Native 0.75.3
/Android 14


-1
投票

视图层次结构不会自动恢复。因此,在

Fragment.onCreateView()
Activity.onCreate()
中,您必须恢复所有视图(从 xml 或以编程方式)。每个包含片段的 ViewGroup 必须具有与第一次创建它时相同的 ID。一旦创建了视图层次结构,Android 就会恢复所有片段,并根据 ID 将它们的视图放入正确的 ViewGroup 中。假设 Android 记住了片段所在的 ViewGroup 的 ID。这种情况发生在
onCreateView()
onStart()
之间。

© www.soinside.com 2019 - 2024. All rights reserved.