使额外的操作栏图标消失

Make the extra action bar icon go away

我已经设法解决了片段事务后操作栏中出现额外图标的问题,但这是一个笨拙的解决方案,我想知道是否有更好的方法来解决它。

我有一个片段 class 层次结构,其中 ContentFragment 是一个抽象片段,它占据了整个屏幕(操作栏除外)及其子 class 贡献了额外的操作栏图标(通过它们各自的 onCreateOptionsMenu()onOptionsItemSelected() 方法)。例如。 ContentFragmentA 贡献 icon AContentFragmentB 贡献 icon BContentFragmentB 可能是也可能不是 child class of [=17] =](如果是,则操作栏将并排包含 icon Aicon B),依此类推。

最初(用户刚刚登录后)屏幕仅包含 ContentFragmentA,操作栏包含 icon A。当用户在应用程序中导航时,其他内容片段(或更准确地说片段交易)被添加到返回堆栈,图标相应地添加或从操作栏中删除。

一切都很好,直到用户决定注销,这会提示应用程序清除整个返回堆栈(在最旧的事务回滚后返回 ContentFragmentA)并立即添加 LoginContentFragment,它为操作栏提供 New Profile icon。但是此时 icon A 也显示在新配置文件图标旁边,我不希望它显示;这就是我面临的问题。它应该在用户注销时消失。

我通过像往常一样清除返回堆栈然后包括一个额外的事务来解决这个问题,该事务将 ContentFragmentA 替换为空白,icon-less 内容片段替换为 setHasOptionsMenu(false),所以 icon A 将在空白片段被替换为 Login fragment 时消失。但我觉得这很笨拙,认为可能有更好的方法。

我已经尝试在片段替换步骤中调用 ContentFragment superclass 中的 Menu.clear()Activity.supportInvalidateOptionsMenu(),但似乎都不起作用。 Menu.clear() 尤其会使所有图标消失,在操作栏中留下 none。

有人知道替代方案吗?

相关代码:

ContentFragment.java:

public abstract class ContentFragment extends Fragment {

    public static interface Callbacks {
        public abstract void setCurrentContentFragment(ContentFragment contentFragment);
    }

    protected Callbacks mCallbacks;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Override
    public void onStart() {
        super.onStart();
        mCallbacks = (Callbacks)getActivity();
        mCallbacks.setCurrentContentFragment(this);
    }

    @Override
    public void onStop() {
        super.onStop();
        mCallbacks = null;
    }

    public boolean handleBackPressed() {
        return false;
    }
}

ContentFragmentA.java:

public abstract class ContentFragmentA extends ContentFragment {

    protected abstract void handleIconATouched();

    ...

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        if (menu.findItem(R.id.icon_a) == null) {
            inflater.inflate(R.menu.icon_a, menu);
        }
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.icon_a) {
            handleIconATouched();
            return true;
        } else {
            return super.onOptionsItemSelected(item);
        }
    }
}

BlankFragment.java:

public class BlankFragment extends LoggedInContentFragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(false);
    }
}

在MainActivity.java中:

...

private void addContentFragmentNotAddingTransactionToBackStackIfCurrentFragment(ContentFragment fragment, boolean clearBackStack) {

    // mCurrentContentFragment changes as the back stack is cleared, thus addToBackStack is calculated before the clearBackStack() step.
    boolean addToBackStack = (false == clearBackStack && (mCurrentContentFragment != null && fragment.getClass() != mCurrentContentFragment.getClass()));

    if (clearBackStack) {
        clearBackStack();
    }

    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    if (addToBackStack) {
        ft.addToBackStack(null);
    }
    ft.replace(R.id.container, fragment);

    ft.commit();

    getSupportFragmentManager().executePendingTransactions();
}

public void clearBackStack() {
    while (getSupportFragmentManager().getBackStackEntryCount() > 0) {
        getSupportFragmentManager().popBackStackImmediate();
    }

    // This is the step I would like to avoid
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.replace(R.id.container, new BlankFragment());
    ft.commit();

    getSupportFragmentManager().executePendingTransactions();
}

...

我解决了这个问题。这是片段事务返回堆栈的问题。我将添加到后台堆栈的事务与未添加到后台堆栈的事务混合在一起,这些导致后台堆栈弹出以意外方式工作并阻止片段被正确删除,因此他们向操作栏添加了额外的图标。 this SO question. The solution I adopted is this one.

中解释了该问题