防止碎片被多次添加到后台堆栈

时间:2014-04-26 00:19:44

标签: android android-fragments fragment back-stack

我目前正在为我即将开发的应用程序奠定基础。有一个动作栏,分配了几个菜单项。每个菜单项都有自己的片段,需要在主活动中显示。但是,我想要" up"当显示除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;
}

这很有用,但是多次按下同一个菜单项时会出现问题,因为片段的新实例每次都会放在后面的堆栈上。防止这种情况发生的最佳方法是什么?显然,我可以检查当前显示的片段是否是被请求的片段,但这会导致大量检查并且是多余的。另一种方式可能是交易代码,但我不确定这是否会导致代码更清晰。

最好的方法是什么?这不是一般问题,或者是我希望应用程序表现出来的方式"错误?因为我个人喜欢" up"动作栏的功能相当多。

3 个答案:

答案 0 :(得分: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 :(得分:0)

你可以通过布尔检查它简单干净......

假设你有4个片段,所以每次你按下其中一个片段时它需要4个布尔检查,其对应的布尔值将为真,下次你按下它时不会添加到片段,直到你后退它...

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;
}

答案 2 :(得分:0)

您可以将所选菜单ID保存为Integer,下次您可以使用前一个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
   }
}

另一种方法是,您可以查看已存在的instance的{​​{1}},只有在它不存在时才替换。

Fragment

Fragment addedFragment = getSupportFragmentManager().findFragmentById(R.id.container); if (addedFragment != null && !addedFragment.getClass().isInstance(fragment)) { // replace the fragment here return true; } 是已添加片段的实例。 addedFragment是基于所选菜单项的实例。

注意:我不建议您使用fragmentgetClass()。但要简单地检查一下,我可以提出建议。