Activity可以通过重写onKeyDown(int keyCode, KeyEvent event),很容易的监听物理返回键事件,而Fragment并不能重写物理键监听事件。在一个Activity多个Fragment页面的应用中,很多时候有必要的监听每个Fragment返回事件,并对每个Fragment做特殊的数据处理。如果将每个Fragment的返回事件都在FragmentActivity中监听消费,那么其onBackPressed()的代码将会比较混乱;
@Override
public void onBackPressed() {
if(selectedFragment.equals(fragmentA)) {
// todo:事件处理
} else if(selectedFragment.equals(fragmentB)) {
// todo:事件处理
} else if(selectedFragment.equals(fragmentC)) {
// todo:事件处理
} else {
// handle by activity
super.onBackPressed();
}
}
那么有没有更好方法分离出各个Fragment的返回事件呢?答案是有的。
需要创建一个抽象类BackHandledFragment,继承于Fragment,该类有个抽象方法onBackPressed(),所有的BackHandledFragment子类都在onBackPressed()中实现自己对返回键的消费处理,onBackPressed()有boolean返回值,用于告诉FragmentActivity,当前的物理返回键是否被消费。
接下来如何告诉宿主FragmentActivity,当前的Fragment对象是哪个呢?以方便FragmentActivity调用当前Fragment对象的onBackPressed()方法。我们可以通过接口来通知宿主FragmentActivity;
public interface IFragmentBackHandled {
abstract void setSelectedFragment(MyFragmentV4 selectedFragment);
}
定义了一个Fragment返回接口,在FragmentActivity中实现该接口,
public class ActivityMain extends MyFragmentActivity implements
IFragmentBackHandled {
private MyFragmentV4 iFragmentBackHandled;
@Override
public void setSelectedFragment(MyFragmentV4 selectedFragment) {
iFragmentBackHandled = selectedFragment;
}
}
接下来,在Fragment的onAttach中获取该接口对象,在Fragment的onStart()方法中调用setFragmentSelected()方法,告诉宿主FragmentActivity,当前栈顶的Fragment对象是哪个。
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if(activity instanceof IFragmentBackHandled){
this.mBackHandled = (IFragmentBackHandled) activity;
}
}
@Override
public void onStart() {
super.onStart();
setSelected();
}
protected void setFragmentSelected(){
mBackHandled.setSelectedFragment(this);
}
如果用show,hide的方式显示/隐藏Fragment,需要在onHiddenChanged(boolean hidden) 中调用setFragmentSelected通知宿主绑定的Fragment对象,因为show/hide的方式并不会再调用onStart()方法。
然后宿主FragmentActivity就可以在onBackPressed()中对back事件进行判断处理,这里我的onBackPressed方法的返回值用于判断是否从当前的Fragment页面退出整个app应用,否则回退栈。
public class ActivityMain extends MyFragmentActivity implements
IFragmentBackHandled {
private MyFragmentV4 iFragmentBackHandled;
@Override
public void setSelectedFragment(MyFragmentV4 selectedFragment) {
iFragmentBackHandled = selectedFragment;
}
@Override
public void onBackPressed() {
if (iFragmentBackHandled != null) {
if (iFragmentBackHandled.isBackPressed() && getSupportFragmentManager()
.getBackStackEntryCount() > 0) {
super.onBackPressed();
return;
}
finish();
}
}
}
另外,网上还流传一些其他方法,比如在Fragment中通过getView()来绑定点击事件。
@Override
public void onResume() {
super.onResume();
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
// handle back button
return true;
}
return false;
}
});
}
具体参考链接如下:
http://stackoverflow.com/questions/22552958/handling-back-press-when-using-fragments-in-android