【问题标题】:Prevent Fragments from being added multiple times to back stack防止 Fragments 被多次添加到 back stack
【发布时间】:2014-04-26 00:19:43
【问题描述】:

我目前正在为我要开发的应用程序布置基础知识。有一个带有几个分配给它的菜单项的操作栏。每个菜单项都有自己的片段,需要在主活动中显示。但是,我希望在显示除 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;
}

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

最好的方法是什么?这不是一个普遍的问题,还是我希望应用程序“表现”错误的方式?因为我个人非常喜欢操作栏的“向上”功能。

【问题讨论】:

    标签: android android-fragments fragment back-stack


    【解决方案1】:

    您可以将选中的菜单id保存为Integer,下次可以将选中的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 是基于您选择的菜单项的实例。

    注意:我真的不建议使用getClass()isInstance。但是为了做一个简单的检查,这是我可以建议的。

    【讨论】:

    • 您不建议getClass() 和/或isInstance() 的原因是什么?看来你们没有我上面提到的问题,那么你们是如何处理操作栏的向上提示的呢?我的项目处于早期阶段,所以如果你给我充分的理由,我很乐意做出相应的调整;)。
    • 逻辑上你可以使用getClass和isInstance。但理论上我理解它是一个糟糕的设计:)
    • 您可以只记住最后选择的菜单 id 并仅在选择的 id 不同时添加片段。
    • 感谢您的回答,但是一旦通过其他方式(而不仅仅是通过选项菜单本身)访问片段,将先前选择的项目保存为整数可能会变得很难看。
    【解决方案2】:

    这就是我解决此问题的方法
    在每个片段上附加一个标签,然后在返回堆栈中添加任何片段之前检查它是否已经在堆栈中可用?
    示例代码

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

    【讨论】:

      【解决方案3】:

      您可以通过布尔值检查其简单明了...

      假设您有 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;
      }
      

      【讨论】:

      • 这样解决当然可以,但老实说我不认为这是一个干净的解决方案,因为它有点多余。
      • @KarolBabioch 那么你唯一的选择是通过标记片段
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-11
      • 1970-01-01
      • 1970-01-01
      • 2014-02-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多