防止片段被添加多次到后退堆栈中

4
我目前正在设计一个应用程序的基础架构,涉及到IT技术。有一个带有几个菜单项的操作栏。每个菜单项都有自己的片段,需要在主活动中显示。然而,我希望当除MainFragment之外的任何片段被显示时,“向上”箭头出现在操作栏中。
我的当前方法基于在actionbar up navigation with fragments中提出的解决方案,看起来像这样:
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
    int id = item.getItemId();

    Fragment fragment = null;

    if (id == R.id.action_identities) {
        fragment = new IdentitiesFragment();
    } else if (id == R.id.action_history) {
        fragment = new HistoryFragment();
    } else if (id == R.id.action_settings) {
        fragment = new SettingsFragment();
    } else if (id == R.id.action_about) {
        fragment = new AboutFragment();
    }

    if (fragment != null) {
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.replace(R.id.container, fragment);
        transaction.addToBackStack(null);
        transaction.commit();
        return true;
    } else {
        return super.onOptionsItemSelected(item);
    }
}

@Override
public void onBackStackChanged()
{
    displayHomeAsUp();
}

private void displayHomeAsUp()
{
    int stackCount = getFragmentManager().getBackStackEntryCount();
    getActionBar().setDisplayHomeAsUpEnabled(stackCount > 0);
}

@Override
public boolean onNavigateUp()
{
    getFragmentManager().popBackStack();
    return true;
}

这个可以很好地工作,但是当多次按下相同的菜单项时会出现问题,因为每次都会将片段的新实例放入返回堆栈中。有什么最好的方法可以防止这种情况发生?显然,我可以检查当前显示的片段是否是被请求的那个片段,但这会导致很多检查并且有点冗余。另一种方式可能是事务标记,但我不确定是否会导致更清晰的代码。
什么是最好的方法?这不是一个通用问题吗,或者说我希望应用程序“表现”方式不正确吗?因为个人非常喜欢操作栏的“向上”功能。
3个回答

1
这是我解决这个问题的方法
在每个片段中附加一个标签,在将任何片段添加到后台堆栈之前,检查它是否已经存在于堆栈中?
示例代码
public void replaceFragment(Fragment fragment, String FRAGMENT_TAG) {
    FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
    fragmentTransaction.replace(R.id.container, fragment, FRAGMENT_TAG);

    if (getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG) == null) {
        if (AppConstants.DEBUG) {
            Toast.makeText(MainActivity.this, "Inside Fragment add", Toast.LENGTH_SHORT).show();
        }
        fragmentTransaction.addToBackStack(FRAGMENT_TAG);
    }

    fragmentTransaction.commit();
}

1
你可以将选择的菜单ID保存为整数,下一次检查所选ID是否与上一个不同,只有在ID不同时才添加片段。
private int previousSelectedId = 0;

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
   int id = item.getItemId();
   if(previousSelectedId == id) {
        return true;   
   }else{
         previousSelectedId = id;
        // add the fragment
   }
}

另一种方法是,您可以检查已经存在的Fragmentinstance,仅在不存在时进行替换。
 Fragment addedFragment = getSupportFragmentManager().findFragmentById(R.id.container);
 if (addedFragment != null &&
        !addedFragment.getClass().isInstance(fragment)) {
        // replace the fragment here
        return true;
    }

addedFragment 是已添加的 fragment 的实例。 fragment 是基于您选择的菜单项的实例。

注意:我不建议使用 getClass()isInstance。但是为了进行简单的检查,这是我可以建议的方法。


你为什么不建议使用 getClass() 和/或 isInstance()?看起来你们没有我上面提到的问题,那么你们是如何处理操作栏的向上箭头的?我的项目处于早期阶段,所以如果你能给我充分的理由,我很乐意进行调整。;) - Karol Babioch
从逻辑上讲,您可以使用getClass和isInstance。但理论上来说,我认为这是一个糟糕的设计 :) - Libin
你可以记住上次选择的菜单ID,只有在所选ID不同时才添加片段。 - Libin
谢谢你的回答,但是将先前选择的项目保存为整数可能会变得很麻烦,一旦片段可以通过其他方式访问而不仅仅通过选项菜单本身。 - Karol Babioch

0

你可以通过布尔值来检查它,这样简单而干净...

假设你有4个片段,所以每次按下其中一个片段时,它对应的布尔值将为true,下一次再按它时,它不会被添加到片段中,直到你回退它...

if (identity == true && id == R.id.action_identities) {
    fragment = new IdentitiesFragment();
    identity = true;
} else if (history == true && id == R.id.action_history) {
    fragment = new HistoryFragment();
    history = true;
} else if (setting == true && id == R.id.action_settings) {
    fragment = new SettingsFragment();
    setting = true;
} else if (about == true && id == R.id.action_about) {
    fragment = new AboutFragment();
    about = true;
}

当然可以这样解决,但说实话,我不认为这是一个干净的解决方案,因为它有点冗余。 - Karol Babioch
@KarolBabioch,那么你唯一的选择就是通过标记片段。 - Rod_Algonquin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接