【问题标题】:What's the best practice fo saving states during navigation across Fragments in an Activity AND refreshing data across all the Fragments?在 Activity 中跨 Fragments 导航期间保存状态并在所有 Fragments 中刷新数据的最佳实践是什么?
【发布时间】:2018-04-13 15:38:12
【问题描述】:

所以我目前的实现如下。基本上我会预加载所有片段,将它们设置为当前Activity 的字段,然后添加或显示片段是否已添加。

    mFeedTopicsFragment = FeedTopicsFragment.getInstance();
    mUserDiscussionsFragment = UserDiscussionsFragment.getInstance(SessionPersistor.getSignedInUserId());
    mUserConversationsFragment = MyConversationsFragment.getInstance(SessionPersistor.getSignedInUserId());

    activityMainNavigation.setOnNavigationItemSelectedListener((MenuItem item) -> {
        switch (item.getItemId()) {
            case R.id.menu_item_go_to_feed_fragment:
                if (getSupportFragmentManager().findFragmentByTag(FeedTopicsFragment.class.getSimpleName()) != null) {
                    getSupportFragmentManager()
                            .beginTransaction()
                            .show(mFeedTopicsFragment)
                            .hide(mUserDiscussionsFragment)
                            .hide(mUserConversationsFragment)
                            .commit();
                } else {
                    getSupportFragmentManager()
                            .beginTransaction()
                            .add(R.id.activity_main_container_fragment, mFeedTopicsFragment, FeedTopicsFragment.class.getSimpleName())
                            .hide(mUserDiscussionsFragment)
                            .hide(mUserConversationsFragment)
                            .commit();
                }
                return true;
            case R.id.menu_item_go_to_user_discussions_fragment:
                if (getSupportFragmentManager().findFragmentByTag(UserDiscussionsFragment.class.getSimpleName()) != null) {
                    getSupportFragmentManager()
                            .beginTransaction()
                            .show(mUserDiscussionsFragment)
                            .hide(mFeedTopicsFragment)
                            .hide(mUserConversationsFragment)
                            .commit();
                } else {
                    getSupportFragmentManager()
                            .beginTransaction()
                            .add(R.id.activity_main_container_fragment, mUserDiscussionsFragment, UserDiscussionsFragment.class.getSimpleName())
                            .hide(mFeedTopicsFragment)
                            .hide(mUserConversationsFragment)
                            .commit();
                }
                return true;
            case R.id.menu_item_go_to_user_conversations_fragment:
                if (getSupportFragmentManager().findFragmentByTag(MyConversationsFragment.class.getSimpleName()) != null) {
                    getSupportFragmentManager()
                            .beginTransaction()
                            .show(mUserConversationsFragment)
                            .hide(mFeedTopicsFragment)
                            .hide(mUserDiscussionsFragment)
                            .commit();
                } else {
                    getSupportFragmentManager()
                            .beginTransaction()
                            .add(R.id.activity_main_container_fragment, mUserConversationsFragment, MyConversationsFragment.class.getSimpleName())
                            .hide(mFeedTopicsFragment)
                            .hide(mUserDiscussionsFragment)
                            .commit();
                }
                return true;

但是,我觉得这是一种不好的方法,因为我通过预加载片段来浪费内存。但是,我不想调用replace 每个FragmentTransaction,因为每次我在片段之间导航时都会调用onCreateView 并强制执行新的API 调用。我不想要这个,只要我留在这个Activity,假设我从FeedTopicsFragment开始,向下滚动到RecyclerView中的第10个项目,从FeedTopicsFragment导航到UserDiscussionsFragment,向下滚动到RecyclerView中的第三项,再回到FeedTopicsFragment,我还是会看到第10项,再回到UserDiscussionsFragment,我会看到第三项。

我正在考虑使用onSaveInstanceState 保存数据的Bundle 并将Bundle 加载到onActivityCreated 中。但恐怕onSaveInstanceState 可能不会被调用,onActivityCreated 也不会。 那么在不创建 Fragment 实例或将其保存为字段并在我离开 Activity 后删除该状态的情况下保存状态的最佳解决方案是什么?

当前每个片段都有一个loadData 方法,该方法在该方法内部调用API 并使用响应数据设置RecyclerViewTextView 等字段。一旦我在 Activity 中执行 SwipeRefresh,它将在每个片段上调用 ​​loadData

我也不确定如何执行此刷新部分,基本上我必须获取所有片段的实例,然后在每个片段上调用 ​​loadData。但一次只有一个片段在activity_main_container_fragment 中。在这种情况下,我认为保存每个片段的实例是有意义的,这样我就可以在这些本地实例上调用 loadData

【问题讨论】:

  • 有多种方法旨在避免每次将 Fragment 附加到 Activity 时都进行 API 调用:保留 Fragments、Loader/LoaderManager(需要习惯,但可以很好地将加载从展示)和最后(到目前为止):LiveData 等。我认为学习如何在应用中使用它们是值得的。
  • 什么是保留片段?只是在 FragmentManager 中按标签保存片段?
  • 不,一点也不。如果 configuration change 发生,保留的 Fragment 不会被销毁。通常它没有(不应该)有任何视图
  • 还是不明白retained Fragments。你有一些我可以查看的资源的链接吗?
  • 只需点击“配置更改”(你不可能在 5 秒内读完所有内容)

标签: android android-fragments android-recyclerview navigation


【解决方案1】:

基本上,您可以在调用 api 之前检查您的 Arraylist 是否为空或为空。

如果list有数据则在本地填写listview,

否则调用api获取数据。

如果你从堆栈中加载片段,那么它也会有它的所有变量,比如 arraylist。

首先你应该考虑调用这个方法来替换你的 Fragment,因为我看到你写了太多的代码。

/**
     * replace or add fragment to the container
     *
     * @param fragment pass android.support.v4.app.Fragment
     * @param bundle pass your extra bundle if any
     * @param popBackStack if true it will clear back stack
     * @param findInStack if true it will load old fragment if found
     */
    public void replaceFragment(Fragment fragment, @Nullable Bundle bundle, boolean popBackStack, boolean findInStack) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        String tag = fragment.getClass().getName();
        Fragment parentFragment;
        if (findInStack && fm.findFragmentByTag(tag) != null) {
            parentFragment = fm.findFragmentByTag(tag);
        } else {
            parentFragment = fragment;
        }
        // if user passes the @bundle in not null, then can be added to the fragment
        if (bundle != null)
            parentFragment.setArguments(bundle);
        else parentFragment.setArguments(null);
        // this is for the very first fragment not to be added into the back stack.
        if (popBackStack) {
            fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        } else {
            ft.addToBackStack(parentFragment.getClass().getName() + "");
        }
        ft.replace(R.id.contenedor_principal, parentFragment, tag);
        ft.commit();
        fm.executePendingTransactions();
    }

像这样使用它

如果您的片段是主页或仪表板片段,那么

Fragment f = new YourFragment();
replaceFragment(f, null, true, true); 

否则

Fragment f = new YourFragment();
replaceFragment(f, null, false, true); 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-09
    相关资源
    最近更新 更多