期望适配器在恢复状态时“新鲜”

时间:2019-06-18 10:09:39

标签: android android-viewpager

我在FragmentStateAdapter中有一个带有多个片段的viewpager2。每当我尝试打开一个新片段,然后使用viewpager2返回到当前片段时,都会出现异常:

Expected the adapter to be 'fresh' while restoring state.

似乎FragmentStateAdapter无法正常恢复其状态,因为它期望它为空。

该如何解决?

8 个答案:

答案 0 :(得分:1)

所以我的问题是我在我的Fragment类字段中创建了FragmentStateAdapter,在该字段中它只创建了一次。所以当我的onCreateView被第二次调用时,我遇到了这个问题。如果我在每个onCreateView调用上重新创建适配器,那么它似乎可以正常工作。

答案 1 :(得分:1)

我在ViewPager2中遇到了同样的问题。经过大量测试不同方法的努力,这对我有用:

public void onExitOfYourFragment() {
    viewPager2.setAdapter(null);
}

当您再次回到片段时:

public void onResumeOfYourFragment() {
    viewPager2.setAdapter(yourAdapter);
}

答案 2 :(得分:1)

可以通过viewPager2.isSaveEnabled = false

进行修复

答案 3 :(得分:0)

在片段中使用ViewPager2时,我也得到了这个java.lang.IllegalStateException: Expected the adapter to be 'fresh' while restoring state.

似乎是因为我在 onCreateView()方法中执行mViewPager2.setAdapter(mFragmentStateAdapter);

我通过将mViewPager2.setAdapter(mMyFragmentStateAdapter);移至我的 onResume()方法来对其进行了修复。

答案 4 :(得分:0)

我通过测试是否等于null来解决了这个问题

if(recyclerView.adapter == null) {recyclerView.adapter = myAdapter}

答案 5 :(得分:0)

我一直在为此苦苦挣扎,以前的答案都没有帮助。

这可能不适用于所有可能的情况,但是在我的情况下,包含ViewPager2的片段是固定的,很少。我通过使用FragmentTransactionshow()和{{1}进行片段切换来解决此问题。 }方法,而不是通常为此推荐的hide()方法。将replace()应用于活动片段,并将show()应用于所有其他片段。这样可以避免重新创建视图以及还原触发问题的状态之类的操作。

答案 6 :(得分:0)

此适配器/视图可用于替代FragmentStatePagerAdapter。

如果您要保存的片段是从Backstack重新进入的,那么使用此适配器将很难实现。

为了防止这种情况,团队安排了许多休息时间,只有上帝知道原因...

他们本可以使用自分离的lifeCycle观察器,该功能已经在其代码中预见到,但是android体系结构中没有地方使用该功能...。

他们应该使用这个未完成的组件来监听全局Fragments生命周期,而不是它的viewLifeCycle,从现在开始,人们可以将监听范围从Fragment扩展到viewLifeCycle。 (附加/分离viewLifeCycle观察者ON_START / ON_STOP)

第二...即使这样做,viewPager本身是建立在recyclerView之上的事实,使得处理片段行为的期望极其困难,这是一种保存状态,时间实例化和明确定义的生命周期(可控/预期破坏)。

此适配器在功能上是矛盾的,它检查viewPager是否已经提供了Fragments,同时在重入时仍需要“新鲜”适配器。

它在退出BackStack时保留片段,同时希望在重新进入时重新创建所有片段。

为防止字段实例化适配器而进行的中断(假设已所有个其他变量已为适当的viewLifeCycle处理(参数的注册/注销和设置及重置)进行了说明)

{
  "_index": "64898361",
  "_type": "_doc",
  "_id": "1",
  "_version": 8,
  "_seq_no": 13,
  "_primary_term": 1,
  "found": true,
  "_source": {
    "survey_id": 15,
    "submission_id": 12069,
    "account_id": 2,
    "answers": [
      {
        "answer_txt": "happy",
        "question_id": 153,
        "skipped": false
      }
    ],
    "id": "15_12069"
  }
}

第二次休息:

@Override
    public final void restoreState(@NonNull Parcelable savedState) {
        if (!mSavedStates.isEmpty() || !mFragments.isEmpty()) {
            throw new IllegalStateException(
                    "Expected the adapter to be 'fresh' while restoring state.");
        }
.....
}

其中mFragmentMaxLifecycleEnforcer在重入时必须为== null,否则会在checkArgument()中引发异常。

第三: 重新进入(视图,从后栈返回)时放置的Fragment垃圾收集器在10秒后被延迟,试图破坏屏幕上的碎片,从而导致内存泄漏所有屏幕外的页面,因为它会杀死控制其生命周期的各自的FragmentManager。

@CallSuper
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
    checkArgument(mFragmentMaxLifecycleEnforcer == null);
    mFragmentMaxLifecycleEnforcer = new FragmentMaxLifecycleEnforcer();
    mFragmentMaxLifecycleEnforcer.register(recyclerView);
}

所有这些都是由于其主要罪魁祸首:构造函数:

private void scheduleGracePeriodEnd() {
    final Handler handler = new Handler(Looper.getMainLooper());
    final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            mIsInGracePeriod = false;
            gcFragments(); // good opportunity to GC
        }
    };

    mLifecycle.addObserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                handler.removeCallbacks(runnable);
                source.getLifecycle().removeObserver(this);
            }
        }
    });

    handler.postDelayed(runnable, GRACE_WINDOW_TIME_MS);
}

答案 7 :(得分:0)

我遇到了同样的问题。

经过一番研究,我发现它与 Adapter 的实例有关。当它被创建为 Fragment 的惰性属性时,它会因该错误而崩溃。

因此在 Adapter 中创建 Fragment::onViewCreated 可以解决它。