Activity可以很容易的得到物理返回鍵的監聽事件,而Fragment卻不能。假設FragmentActivity有三個Fragment,一般安卓用戶期望點擊返回鍵會一層層返回到FragmentActivity。當然,我們可以將每個Fragment對應的Transaction放到BackStack中,但是如果每個Fragment有對返回事件的特殊消費,那麼在FragmentActivity的onBackPressed()中的代碼就會比較混亂,例如:
- @Override
- public void onBackPressed() {
- if(selectedFragment.equals(fragmentA) && fragmentA.hasExpandedRow()) {
- fragmentA.collapseRow();
- } else if(selectedFragment.equals(fragmentA) && fragmentA.isShowingLoginView()) {
- fragmentA.hideLoginView();
- } else if(selectedFragment.equals(fragmentA)) {
- popBackStack();
- } else if(selectedFragment.equals(fragmentB) && fragmentB.hasCondition1()) {
- fragmentB.reverseCondition1();
- } else if(selectedFragment.equals(fragmentB) && fragmentB.hasCondition2()) {
- fragmentB.reverseCondition2();
- } else if(selectedFragment.equals(fragmentB)) {
- popBackStack();
- } else {
- // handle by activity
- super.onBackPressed();
- }
- }
首先創建一個抽象類BackHandledFragment,該類有一個抽象方法onBackPressed(),所有BackHandledFragment的子類在onBackPressed方法中處理各自對Back事件的消費邏輯。onBackPressed返回布爾值,宿主FragmentActivity將會根據該方法的返回值判斷子Fragment是否有消費Back事件。此外,宿主FragmentActivity還會保持一份當前Fragment的引用,當用戶按下Back鍵時,宿主Activity會判斷當前Fragment是否需要消費該事件,如果沒有Fragment消費纔會自己消費。
- public abstract class BackHandledFragment extends Fragment {
- protected BackHandledInterface mBackHandledInterface;
- /**
- * 所有繼承BackHandledFragment的子類都將在這個方法中實現物理Back鍵按下後的邏輯
- * FragmentActivity捕捉到物理返回鍵點擊事件後會首先詢問Fragment是否消費該事件
- * 如果沒有Fragment消息時FragmentActivity自己纔會消費該事件
- */
- protected abstract boolean onBackPressed();
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if(!(getActivity() instanceof BackHandledInterface)){
- throw new ClassCastException("Hosting Activity must implement BackHandledInterface");
- }else{
- this.mBackHandledInterface = (BackHandledInterface)getActivity();
- }
- }
- @Override
- public void onStart() {
- super.onStart();
- //告訴FragmentActivity,當前Fragment在棧頂
- mBackHandledInterface.setSelectedFragment(this);
- }
- }
- public interface BackHandledInterface {
- public abstract void setSelectedFragment(BackHandledFragment selectedFragment);
- }
宿主FragmentActivity就可以在onBackPressed()方法中對Back事件進行判斷處理了。
- public class MainActivity extends FragmentActivity implements BackHandledInterface{
- private BackHandledFragment mBackHandedFragment;
- private boolean hadIntercept;
- @Override
- public void setSelectedFragment(BackHandledFragment selectedFragment) {
- this.mBackHandedFragment = selectedFragment;
- }
- @Override
- public void onBackPressed() {
- if(mBackHandedFragment == null || !mBackHandedFragment.onBackPressed()){
- if(getSupportFragmentManager().getBackStackEntryCount() == 0){
- super.onBackPressed();
- }else{
- getSupportFragmentManager().popBackStack();
- }
- }
- }
- }