在片段之间导航时保​​存状态

时间:2018-03-16 09:25:35

标签: java android android-fragments onsaveinstancestate

我正在处理一个应用程序,我有一个带有NavigationDrawer的菜单,可以在片段之间导航。在其中一个片段中,我调用后端,然后将结果保存在列表中。当我导航到另一个片段并返回时,结果消失了,但我想暂时保存列表的内容。 我想使用onSaveInstanceState(),但这种方法似乎永远不会被调用。我还会查看当我返回片段时数据是否仍在字段中,但是事实并非如此。我认为我对FragmentManager做错了什么,但我不确定。

这是用于碎片事务的方法:

private void openFragment(Class fragmentClass) {
    Fragment fragment;
    try {
        fragment = (Fragment) fragmentClass.newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
        e.printStackTrace();
        return;
    }
    contentFrame.removeAllViews();
    FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager.beginTransaction().replace(R.id.contentFrame,fragment).commit();
}

我使用switch case确定Fragment的类并将其发送到此方法。

我可能想出一个修复这个的hacky-snappy方法,但是我想在没有太多hacky-snappy代码的情况下解决这个问题。

我希望有人知道如何解决这个问题。提前谢谢。

修改

这是我的片段类:

public class LGSFragment extends Fragment {

    @BindView(R.id.rvLGS)
    RecyclerView rvLGS;

    private List<LGS> lgsList;
    private LGSAdapter adapter;

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //I debugged here and all fields were null at this point
        View view = inflater.inflate(R.layout.fragment_lgs,container,false);
        ButterKnife.bind(this, view);
        lgsList = new ArrayList<>();
        LinearLayoutManager manager = new LinearLayoutManager(getContext());
        rvLGS.setLayoutManager(manager);
        adapter = new LGSAdapter(lgsList);
        rvLGS.setAdapter(adapter);
        getDatabaseLGSs();
        return view;
    }

    /**
     * Method to load in the LGSs from the database
     */
    private void getDatabaseLGSs() {
        String collection = getString(R.string.db_lgs);
        FireStoreUtils.getAllDocumentsConverted(collection, LGS.class, new OperationCompletedListener() {
            @Override
            public void onOperationComplete(Result result, Object... data) {
                if (result == Result.SUCCESS) {
                    lgsList.clear();
                    List<LGS> newLGSs = (List<LGS>) data[0];
                    List<String> ids = (List<String>) data[1];
                    int i = 0;
                    for (LGS lgs : newLGSs) {
                        lgs.setId(ids.get(i));
                        lgsList.add(lgs);
                        i++;
                    }
                    adapter.notifyDataSetChanged();
                }
            }
        });
    }


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

2 个答案:

答案 0 :(得分:2)

onSaveInstanceState未被调用,因为没有理由,当您在片段之间导航时,较旧的片段不会被销毁,直到操作系统需要他们使用的空间(记忆不足)。

首先创建一个后端堆栈以保留片段或只在addtoBackStack结束时调用fragmentTransaction,然后将列表启动和数据请求移动到onCreate,这样它只在创建片段时调用:

    lgsList = new ArrayList<>();
    getDatabaseLGSs();

之后每次回到片段时,都会使用可用数据重新创建视图。

<强>更新 您可以将片段添加到backstack,然后使用相应的tag检索它,而不是自己保留引用。这个让我们的fragmentManager自己管理缓存。第二次访问片段时,它不会被重新创建:

@Override
public void onNavigationDrawerItemSelected(@NonNull MenuItem item) {
    if (item.isChecked())
        return;

    item.setChecked(true);
    setTitle(item.getTitle());

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction transaction = fragmentManager.beginTransaction();
    Fragment currentlyShown = fragmentManager.findFragmentByTag(currentlyShownTag);

    Fragment dest;
    switch (item.getItemId()){
        case R.id.nav_lgs:
            dest = fragmentManager.findFragmentByTag(LGSFragment.class.getName());
            if (dest == null) {
                Log.d("TRANSACTION", "instanciating new fragment");
                dest = new LGSFragment();
                currentlyShownTag = LGSFragment.class.getName();
                transaction.add(R.id.contentFrame, dest, LGSFragment.class.getName());
            }
            break;
            ...


    }

    if(currentlyShown != null)
        transaction.hide(currentlyShown);

    transaction.show(dest);
    transaction.commit();
    drawerLayout.closeDrawers();
    return true;
}

答案 1 :(得分:2)

修改 虽然此解决方案工作正常,但此解决方案使用了一些不良做法,我建议使用已接受的解决方案。

我在Keivan Esbatirafid059的帮助下解决了这个问题(谢谢!)

由于我只有4个片段,我在MainActivity中保留了每个片段的实例,我还有一个变量来跟踪当前的片段。每次打开片段时,我都会使用FragmentManager隐藏当前片段并在事务中调用.hide()。然后,如果片段是新的片段,我在事务中调用.add(),否则我在事务中调用.show

onNavigationItemSelected()方法的代码(当用户选择菜单中的项目时触发):

public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    if (!item.isChecked()) {
        item.setChecked(true);
        setTitle(item.getTitle());
        switch (item.getItemId()) {
            case R.id.nav_lgs: {
                if (lgsFragment == null) {
                    lgsFragment = new LGSFragment();
                    openFragment(lgsFragment, FragmentTag.LGS.toString());
                } else {
                    openFragment(lgsFragment, "");
                }
                currentFragmentTag = FragmentTag.LGS;
                break;
            }
            case R.id.nav_users: {
                if (userFragment == null) {
                    userFragment = new UserFragment();
                    openFragment(userFragment, FragmentTag.USERS.toString());
                } else {
                    openFragment(userFragment, "");
                }
                currentFragmentTag = FragmentTag.USERS;
                break;
            }
            case R.id.nav_profile: {
                if (profileFragment == null) {
                    profileFragment = new ProfileFragment();
                    openFragment(profileFragment, FragmentTag.PROFILE.toString());
                } else {
                    openFragment(profileFragment, "");
                }
                currentFragmentTag = FragmentTag.PROFILE;
                break;
            }
            case R.id.nav_my_lgs: {
                if (myLGSFragment == null) {
                    myLGSFragment = new MyLGSFragment();
                    openFragment(myLGSFragment, FragmentTag.MY_LGS.toString());
                } else {
                    openFragment(myLGSFragment, "");
                }
                currentFragmentTag = FragmentTag.MY_LGS;
                break;
            }
            default: {
                if (lgsFragment == null) {
                    lgsFragment = new LGSFragment();
                    openFragment(lgsFragment, FragmentTag.LGS.toString());
                } else {
                    openFragment(lgsFragment, "");
                }
                currentFragmentTag = FragmentTag.LGS;
                break;
            }
        }
    }
    drawerLayout.closeDrawers();
    return true;
}

上面使用的openFragment()方法:

private void openFragment(Fragment fragment, String tag) {
    FragmentManager fragmentManager = getSupportFragmentManager();
    if (currentFragmentTag != FragmentTag.NO_FRAGMENT) {
        fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag(currentFragmentTag.toString())).commit();
    }
    if (!tag.equals("")) {
        fragmentManager.beginTransaction().add(R.id.contentFrame,fragment,tag).commit();
    } else {
        fragmentManager.beginTransaction().show(fragment).commit();
    }
}

onCreate()中设置:

currentFragmentTag = FragmentTag.NO_FRAGMENT;
if (lgsFragment == null) {
    lgsFragment = new LGSFragment();
    openFragment(lgsFragment, FragmentTag.LGS.toString());
} else {
    openFragment(lgsFragment, "");
}
currentFragmentTag = FragmentTag.LGS;