【问题标题】:How to keep only one instance of a fragment, when switching with NavigationDrawer?使用 NavigationDrawer 切换时,如何只保留片段的一个实例?
【发布时间】:2014-07-26 14:35:52
【问题描述】:

我的应用程序以 AddressFragment 开头。从 NavigationDrawer 我开始(除其他外)一个 new AddressFragment :

getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, new AddressFragment())
                .addToBackStack(null)
                .commit();

但我宁愿回到第一个实例。我怎么能这样做?

或者更笼统地说,我怎样才能知道片段的实例是否已经存在,然后启动它,如果存在,否则创建一个?

【问题讨论】:

  • 嗨,迈克尔,你的推特账号是什么..

标签: android android-fragments


【解决方案1】:

在创建片段时为其设置标签,然后您可以通过片段管理器找到它并相应地替换/创建。

FragmentManager fManager = getFragmentManager();
FragmentTransaction fTransaction = fManager.beginTransaction();
Fragment fragment = fManager.findFragmentByTag("uniqueTag");

// If fragment doesn't exist yet, create one
if (fragment == null) {
    fTransaction.add(R.id.fragment_list, new ListFrag(), "uniqueTag");
}
else { // re-use the old fragment
    fTransaction.replace(R.id.fragment_list, fragment, "uniqueTag");
}

【讨论】:

    【解决方案2】:

    第一步:

    优化当前代码,让 Fragment 拥有自己的“TAG”

    getSupportFragmentManager().beginTransaction()
                    .replace(R.id.container, new AddressFragment())
                    .addToBackStack(**AddressFragment.class.getName()**)
                    .commit();
    

    第二步:

    在您的应用程序流程中,您需要确定片段是否存在:

    public static boolean isFragmentInBackstack(final FragmentManager fragmentManager, final String fragmentTagName) {
        for (int entry = 0; entry < fragmentManager.getBackStackEntryCount(); entry++) {
            if (fragmentTagName.equals(fragmentManager.getBackStackEntryAt(entry).getName())) {
                return true;
            }
        }
        return false;
    }
    

    第三步:

    执行片段操作

    if (exists) {
        // Fragment exists, go back to that fragment
        //// you can also use POP_BACK_STACK_INCLUSIVE flag, depending on flow
        mFragmentManager.popBackStackImmediate(AddressFragment.class.getName(), 0);
    
    } else {
        // Fragment doesn't exist
        // STEP 1 + additional backstack management
    }
    

    【讨论】:

    • 我解决了标记片段而不是返回堆栈的解决方案。看起来也很有趣,下次可以试试。
    • 事实证明,如果您在切换到现有片段时不弹出回栈,则 Back 稍后会出现错误。因此,我在重用现有片段时添加了一个 popBackStackImmediate。
    • 在弹出回栈的情况下,您将丢失“片段的一个实例”,正如作者所希望的那样
    【解决方案3】:

    这是经过测试的答案,希望对您有所帮助 首先在 MainActivity 中全局设置这些字段

    private static final int TIME_INTERVAL = 2000; 
    private long mBackPressed;
    private FragmentManager fm;
    private FragmentTransaction ft;
    private DrawerLayout drawer;
    

    现在在 onNavigationItemSelected() 中这样实现

        @Override
    public boolean onNavigationItemSelected(MenuItem item) {
    Fragment fragment = null;
    Class fragmentClass = null;
    switch (item.getItemId()) {
    case R.id.nav_home:
    fragmentClass = Fragment.class;//this is MainAvctivty extends AppCompatActivity
    break;
    case R.id.nav_f1:
    fragmentClass = FragmentOne.class;
    break;
    case R.id.nav_f2:
    fragmentClass = FragmentTwo.class;
    break;
    case R.id.nav_f3:
    fragmentClass = FragmentThree.class;
    break;
    case R.id.nav_f4:
    fragmentClass = FragmentFour.class;
    break;
    case R.id.nav_f5:
    fragmentClass = FragmentFive.class;
    break;
    default:
    fragmentClass = Fragment.class;
    }
    try {
    fragment = (Fragment) fragmentClass.newInstance();
    } catch (Exception e) {e.printStackTrace();}
    //Insert the fragment by replacing any existing fragment
    fm = getSupportFragmentManager();
    ft = fm.beginTransaction();
    ft.replace(R.id.frame_container, fragment);
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    ft.addToBackStack(null);
    ft.commit();
    item.setChecked(true);
    setTitle(item.getTitle());
    drawer.closeDrawers();
    return true;
    }
    

    现在像下面这样处理onbackpressed

    @Override
    public void onBackPressed() {
    if (drawer != null) {
    fm = getSupportFragmentManager();
    ft = fm.beginTransaction();
    if (drawer.isDrawerOpen(GravityCompat.START)) {
    drawer.closeDrawer(GravityCompat.START);
    } else if (fm.getBackStackEntryCount() > 0) {
    fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
    ft.commit();
    } else if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis()) {
    super.onBackPressed();
    } else {
    Toast.makeText(this,"Press again to exit the app",Toast.LENGTH_SHORT).show();
    }
    mBackPressed = System.currentTimeMillis();
    }
    }
    

    【讨论】:

      【解决方案4】:

      第一次创建带有标签的片段。

      当你想替换它时,尝试获取带有标签的片段,如果它返回 null 你创建一个新的

      【讨论】:

      • 不,如果您在add()/replace() 之后立即调用findFragmentByTag(),您仍然会得到null。因为愚蠢的Android还没有处理请求。所以这不是解决方案
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多