回栈事务后如何持久化分片数据?

Posted

技术标签:

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

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

事实:

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

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

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

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

注意:可能related/duplicate question

【问题讨论】:

现在我唯一的选择是:isFromBackStack = getActivity().getSupportFragmentManager().getBackStackEntryCount() > 0。我想要一些更清洁的东西,这对我来说就像一个黑客。另外,我没有从前一个片段实例中得到Bundle 【参考方案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 时加载的列表。你知道这是否会导致任何内存问题吗? 将它保存在活动中对我来说似乎不是一个好主意。活动总是被逻辑阻塞。

以上是关于回栈事务后如何持久化分片数据?的主要内容,如果未能解决你的问题,请参考以下文章

mycat部署安装及实现数据持久化的分库分表

Redis

5.ElasticSearch数据写入与删除

如何使用事务回栈来弹出片段?

25.redis

Redis实践