如何在两个片段之间切换,而不是每次都重新创建片段?

Tes*_*101 40 android android-fragments

我正在开发一个Android应用程序,它使用导航抽屉在两个片段之间切换.但是,每次切换时,片段都会被完全重新创建.

这是我主要活动的代码.

/* The click listener for ListView in the navigation drawer */
private class DrawerItemClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        selectItem(position);
    }
}

private void selectItem(int position) {
    android.support.v4.app.Fragment fragment;
    String tag;
    android.support.v4.app.FragmentManager; fragmentManager = getSupportFragmentManager();

    switch(position) {
        case 0:
            if(fragmentManager.findFragmentByTag("one") != null) {
                fragment = fragmentManager.findFragmentByTag("one");
            } else {
                fragment = new OneFragment();
            }
            tag = "one";
            break;
        case 1:
            if(fragmentManager.findFragmentByTag("two") != null) {
                fragment = fragmentManager.findFragmentByTag("two");
            } else {
                fragment = new TwoFragment();
            }
            tag = "two";
            break;
    }

    fragment.setRetainInstance(true);
    fragmentManager.beginTransaction().replace(R.id.container, fragment, tag).commit();

    // update selected item and title, then close the drawer
    mDrawerList.setItemChecked(position, true);
    setTitle(mNavTitles[position]);
    mDrawerLayout.closeDrawer(mDrawerList);
}
Run Code Online (Sandbox Code Playgroud)

我已经设置了一些调试日志记录,每次调用selectItem时,一个片段被销毁,而另一个片段被创建.

有没有办法阻止重新创建片段,而只是重用它们?

Tes*_*101 47

在@meredrica指出replace()破坏片段之后,我回过了FragmentManager文档.这是我提出的解决方案,似乎正在发挥作用.

/* The click listener for ListView in the navigation drawer */
private class DrawerItemClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        selectItem(position);
    }
}

private void selectItem(int position) {
    android.support.v4.app.FragmentManager; fragmentManager = getSupportFragmentManager();

    switch(position) {
        case 0:
            if(fragmentManager.findFragmentByTag("one") != null) {
                //if the fragment exists, show it.
                fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag("one")).commit();
            } else {
                //if the fragment does not exist, add it to fragment manager.
                fragmentManager.beginTransaction().add(R.id.container, new OneFragment(), "one").commit();
            }
            if(fragmentManager.findFragmentByTag("two") != null){
                //if the other fragment is visible, hide it.
                fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("two")).commit();
            }
            break;
        case 1:
            if(fragmentManager.findFragmentByTag("two") != null) {
                //if the fragment exists, show it.
                fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag("two")).commit();
            } else {
                //if the fragment does not exist, add it to fragment manager.
                fragmentManager.beginTransaction().add(R.id.container, new TwoFragment(), "two").commit();
            }
            if(fragmentManager.findFragmentByTag("one") != null){
                //if the other fragment is visible, hide it.
                fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("one")).commit();
            }
            break;
    }

    // update selected item and title, then close the drawer
    mDrawerList.setItemChecked(position, true);
    setTitle(mNavTitles[position]);
    mDrawerLayout.closeDrawer(mDrawerList);
}
Run Code Online (Sandbox Code Playgroud)

我也加了这个,但我不确定是否有必要.

@Override
public void onDestroy() {
    super.onDestroy();
    FragmentManager fragmentManager = getSupportFragmentManager();
    if(fragmentManager.findFragmentByTag("one") != null){
        fragmentManager.beginTransaction().remove(fragmentManager.findFragmentByTag("one")).commit();
    }
    if(fragmentManager.findFragmentByTag("two") != null){
        fragmentManager.beginTransaction().remove(fragmentManager.findFragmentByTag("two")).commit();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 实际上,我只是对其进行了测试,并且效果很好。所以是的,它仍然有效。 (2认同)

pat*_*ckf 16

attach/detach方法与标记一起使用:

分离将破坏视图hirachy但保持状态,就像在后台上; 这将使"不可见"片段具有更小的内存占用.但请注意,您需要正确实现片段生命周期(您应该首先执行此操作)

从UI中分离给定的片段.这与放在后台堆栈时的状态相同:片段从UI中删除,但片段管理器仍在主动管理其状态.进入此状态时,其视图层次结构将被销毁.

第一次添加片段

FragmentTransaction t = getSupportFragmentManager().beginTransaction();
t.add(android.R.id.content, new MyFragment(),MyFragment.class.getSimpleName());
t.commit();
Run Code Online (Sandbox Code Playgroud)

然后你分开它

FragmentTransaction t = getSupportFragmentManager().beginTransaction();
t.detach(MyFragment.class.getSimpleName());
t.commit();
Run Code Online (Sandbox Code Playgroud)

如果换回,再次附加,状态将被保留

FragmentTransaction t = getSupportFragmentManager().beginTransaction();
t.attach(getSupportFragmentManager().findFragmentByTag(MyFragment.class.getSimpleName()));
t.commit();
Run Code Online (Sandbox Code Playgroud)

但你总是要检查片段是否已添加,如果没有,则添加它,否则只需附加它:

if (getSupportFragmentManager().findFragmentByTag(MyFragment.class.getSimpleName()) == null) {
    FragmentTransaction t = getSupportFragmentManager().beginTransaction();
    t.add(android.R.id.content, new MyFragment(), MyFragment.class.getSimpleName());
    t.commit();
} else {
    FragmentTransaction t = getSupportFragmentManager().beginTransaction();
    t.attach(getSupportFragmentManager().findFragmentByTag(MyFragment.class.getSimpleName()));
    t.commit();
}
Run Code Online (Sandbox Code Playgroud)

  • Android可能会分离未使用的片段,如果你隐藏/显示它你会有一个强引用它,所以这种方法更有效. (4认同)

mer*_*ica 5

replace方法会破坏你的碎片.一种解决方法是将它们设置为Visibility.GONE,另一种(不太容易)的方法是将它们保存在变量中.如果这样做,请确保不要左右泄漏内存.