【问题标题】:How to persist fragment data after backstack transactions?回栈事务后如何持久化分片数据?
【发布时间】:2013-06-19 14:06:51
【问题描述】:

我有一个活动,包含片段“列表”,单击其中一个项目时,它会将自身替换为“内容”片段。当用户使用后退按钮时,他会再次被带到“列表”片段。
问题在于,无论我如何尝试持久化数据,片段都处于默认状态。

事实:

  1. 两个片段都是通过public static TheFragment newInstance(Bundle args)setArguments(args)Bundle args = getArguments()创建的
  2. 两个片段位于同一级别,直接位于父活动的FrameLayout 内(即不是嵌套片段)
  3. 我不想打电话给setRetainInstance,因为我的活动是一个主/详细信息流,它在大屏幕上有一个2 窗格布局。 7" 平板电脑有 1 个纵向窗格和 2 个横向窗格。如果我保留“列表”片段实例,它会(我认为)屏幕旋转搞砸
  4. 当用户点击'list'片段中的某一项时,'content'片段通过FragmentTransaction#replace(int, Fragment, String)显示,ID相同,标签不同
  5. 我确实覆盖了onSaveInstanceState(Bundle),但这并不是由框架总是调用的,如per the doc“在很多情况下,片段可能大部分被拆除(例如就像放置在没有显示 UI 的后堆栈上时一样),但在其拥有的 Activity 实际需要保存其状态之前,它的状态不会被保存。"
  6. 我正在使用支持库

从上面的第5条,我猜低端设备需要在片段事务后恢复内存可能会调用Fragment#onSaveInstanceState(Bundle)。但是,在我的测试设备(Galaxy Nexus 和 Nexus 7)上,该框架不会调用该方法。所以这不是一个有效的选择。

那么,我怎样才能保留一些片段数据呢?传递给Fragment#onCreateFragment#onActivityCreated 等的包总是null

因此,我无法从全新的片段启动到返回堆栈恢复。

注意:可能related/duplicate question

【问题讨论】:

  • 现在我唯一的选择是:isFromBackStack = getActivity().getSupportFragmentManager().getBackStackEntryCount() > 0。我想要一些更清洁的东西,这对我来说就像一个黑客。另外,我没有从前一个片段实例中得到Bundle

标签: android android-fragments back-stack


【解决方案1】:

这似乎不对,但这是我最终的做法:

public class MyActivity extends FragmentActivity {
    private Bundle mMainFragmentArgs;

    public void saveMainFragmentState(Bundle args) {
        mMainFragmentArgs = args;
    }

    public Bundle getSavedMainFragmentState() {
        return mMainFragmentArgs;
    }

    // ...
}

在主要片段中:

public class MainFragment extends Fragment {
    @Override
    public void onActivityCreated(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Bundle args = ((MyActivity) getActivity()).getSavedMainFragmentState();

        if (args != null) {
            // Restore from backstack
        } else if (savedInstanceState != null) {
            // Restore from saved instance state
        } else {
            // Create from fragment arguments
            args = getArguments();
        }

        // ...
    }

    // ...

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Bundle args = new Bundle();
        saveInstance(args);
        ((MyActivity) getActivity()).saveMainFragmentState(args);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        saveInstance(outState);
    }

    private void saveInstance(Bundle data) {
        // put data into bundle
    }
}

有效!

  • 如果从backstack返回,fragment使用onDestroyView中保存的参数
  • 如果从另一个应用程序/进程/内存不足返回,该片段将从onSaveInstanceState恢复
  • 如果是第一次创建,分片使用setArguments中设置的参数

涵盖所有事件,并始终保留最新信息。

实际上更复杂,它是基于interface的,监听器是从onAttach/onDetach取消/注册的。但原理是一样的。

【讨论】:

  • 哇。我只是在学习 android,所以我怀疑我错过了一些东西。也许我应该读一本书。我无法让数据在片段的整个生命周期内持续存在。但这可以解决问题。谢谢
  • 您可以在删除/替换之前使用 FragmentManager 的 saveFragmentInstanceState() 来代替在 onDestroyView 中为 backstack 情况保存状态。这将调用 onSaveInstanceState()。这允许您将状态持久性代码保留在一个位置。
  • 我有一个类似的方法,我需要保存以前在替换 fragment 时加载的列表。你知道这是否会导致任何内存问题吗?
  • 将它保存在活动中对我来说似乎不是一个好主意。活动总是被逻辑阻塞。
猜你喜欢
  • 1970-01-01
  • 2021-03-05
  • 2014-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-17
相关资源
最近更新 更多