我可以从添加到ActionBar
的NavigationDrawerFragment
中成功拦截MainActivity
主页按钮,如下所示:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (!loggedIn() && item.getItemId() == android.R.id.home) {
login();
return true;
}
return super.onOptionsItemSelected(item);
}
但是,在我的
ComposeActivity
和ComposeFragment
中,这不起作用。 fragment 上未调用onOptionsItemSelected
。我已经调试了代码,问题似乎归结于Android支持库的设计。看来
FragmentActivity
和Activity
都有它们自己对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版本为目标并删除了支持库,则好像不会发生。
关于此问题的解决方法,我想我可以:
ComposeActivity
的onOptionsItemSelected
中,我可以将事件手动传递给我的每个 fragment ,查看它们是否可以在调用super之前对其进行处理。 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);
}