我可以从添加到ActionBarNavigationDrawerFragment中成功拦截MainActivity主页按钮,如下所示:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (!loggedIn() && item.getItemId() == android.R.id.home) {
        login();
        return true;
    }
    return super.onOptionsItemSelected(item);
}

但是,在我的ComposeActivityComposeFragment中,这不起作用。 fragment 上未调用onOptionsItemSelected

我已经调试了代码,问题似乎归结于Android支持库的设计。看来FragmentActivityActivity都有它们自己对FragmentManager的引用。
FragmentActivity首先检查Activity是否可以处理该事件,然后再检查其任何 fragment ,这与docs一致:
/**
 * Dispatch context and options menu to fragments.
 */
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
    if (super.onMenuItemSelected(featureId, item)) {
        return true;
    }

    switch (featureId) {
        case Window.FEATURE_OPTIONS_PANEL:
            return mFragments.dispatchOptionsItemSelected(item);

        case Window.FEATURE_CONTEXT_MENU:
            return mFragments.dispatchContextItemSelected(item);

        default:
            return false;
    }
}

如下面的代码 fragment 所示,Activity在检查主页按钮或其任何 fragment 是否可以处理事件之后,将其作为最后的选择。但是对FragmentManager的引用不包含任何 fragment ,这些 fragment 在FragmentActivity的管理器中。因此,如果设置了Activity,则该事件将被ActionBar.DISPLAY_HOME_AS_UP类吞噬。
public boolean onMenuItemSelected(int featureId, MenuItem item) {
    /* ... */
    if (onOptionsItemSelected(item)) {
        return true;
    }
    if (mFragments.dispatchOptionsItemSelected(item)) {
        return true;
    }
    if (item.getItemId() == android.R.id.home && mActionBar != null &&
            (mActionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
        if (mParent == null) {
            return onNavigateUp();
        } else {
            return mParent.onNavigateUpFromChild(this);
        }
    }
    return false;
    /* ... */
}

事实证明,作为我的应用程序的根并使用抽屉导航的MainActivity没有设置此标志,因此也没有吞噬该事件。但是我的ComposeActivity具有父 Activity ,因此我需要设置此标志,因此无法拦截操作栏的主页按钮。



:这是支持库中的错误吗? 如果我以较新的Android版本为目标并删除了支持库,则好像不会发生。

关于此问题的解决方法,我想我可以:
  • 在我的ComposeActivityonOptionsItemSelected中,我可以将事件手动传递给我的每个 fragment ,查看它们是否可以在调用super之前对其进行处理。
  • 重写onMenuItem在ComposeActivity中选择并执行相同的操作。

  • 有人遇到过吗?我应该在某个地方记录错误吗?还有其他解决此问题的方法的想法吗?

    最佳答案

    如您所解释的那样,由于在Android中如何调度事件,因此子 fragment 似乎永远不会截获该事件,因为该事件首先被Activity占用。

    这是一种解决方法,但是我正在做的是将事件传递给子 fragment ,然后再在Activity中进行处理。

    在 Activity 中:

        @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Due to a problem of not being able to intercept android.R.id.home in fragments,
        // we start passing the event to the currently displayed fragment.
        // REF: http://stackoverflow.com/questions/21938419/intercepting-actionbar-home-button-in-fragment
        final Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.XXXXXXX);
        if (currentFragment != null && currentFragment.onOptionsItemSelected(item)) {
            return true;
        }
    
        switch (item.getItemId()) {
            case XXX:
                ...
                return true;
            case YYY:
                ...
                return true;
            default:
                break;
        }
        return super.onOptionsItemSelected(item);
    }
    

    09-28 10:14