天天看點

關于Fragment中傳回鍵(onBackPressed)的處理

關于Fragment中傳回鍵(onBackPressed)的處理

我們在Android開發中怎麼處理傳回鍵的?常見的兩種方法:
  • 在Activity中實作如下代碼,來監聽“傳回鍵”
@Override
    public void onBackPressed() {
        // 這裡做傳回鍵的處理
        super.onBackPressed();
    }
           
  • 或者
@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {

            //這裡做傳回鍵的處理
        }

        return super.onKeyDown(keyCode, event);
    }
           
在Activity中,我們可以通過以上兩個方法處理傳回鍵的邏輯,可是在fragment中,沒有以上兩個方法。我們怎麼單獨處理每個fragment中的傳回鍵呢?

這裡提供一個方法,可供參考:

如上文所叙述的那樣,在Activity中實作如下代碼
package com.example.onbackpressed;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;

public class MainActivity extends ActionBarActivity implements BackHandledInterface{

    private PlaceholderFragment mPlaceholderFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (savedInstanceState == null) {
            FragmentTransaction beginTransaction = getFragmentManager()
                    .beginTransaction();
            beginTransaction.add(R.id.container, new PlaceholderFragment(),
                    "placeholderfragment");
            beginTransaction.commit();
        }
    }

    @Override
    public void setSelectedFragment(PlaceholderFragment selectedFragment) {
        this.mPlaceholderFragment = selectedFragment;
    }


    @Override
    public void onBackPressed() {

        if (mPlaceholderFragment == null|| !mPlaceholderFragment.onBackPressed()) {
            //處理
        } else {
            //處理
            super.onBackPressed();
        }
    }

    }
           
由以上代碼可以看到,在Activity剛被建立時,就執行個體化了fragment
package com.example.onbackpressed;

import android.app.Activity;
import android.app.Fragment;

public class PlaceholderFragment extends Fragment {

    private BackHandledInterface mBackHandledInterface;
    private int i=;

    @Override
    public void onAttach(Activity activity) {

        super.onAttach(activity);

        if (!(getActivity() instanceof BackHandledInterface)) {
            throw new ClassCastException(
                    "Hosting Activity must implement BackHandledInterface");
        } else {
            this.mBackHandledInterface = (BackHandledInterface) getActivity();
        }
    }

    @Override
    public void onStart() {
        mBackHandledInterface.setSelectedFragment(this);
        super.onStart();
    }


    public boolean onBackPressed() {
        i++;

        return i>;
    }

}
           
在fragment中,fragment剛被Activity建立關聯時,fragment會執行生命周期的onAttach方法,在該拿到了Activity的執行個體,判斷Activity是不是實作了BackHandledInterface接口,如果已經實作(我把他了解為繼承),這裡可以通過面向接口的思想,把Activity轉換成“父類”,(如果沒有實作BackHandledInterface,報出類型轉換異常)。

BackHandledInterface 接口代碼如下:

package com.lemeng.weishi.interfaces;

import com.lemeng.weishi.PlaceholderFragment;

public interface BackHandledInterface {

    public abstract void setSelectedFragment(PlaceholderFragment selectedFragment);
}
           

接着fragment會執行生命周期的onStart方法,通過BackHandledInterface接口(父類)引用調用自己的setSelectedFragment方法,把fragment自己的執行個體引用傳遞個了接口的“子類”(Activity)。

這樣做的好處是,Activity那邊拿到的執行個體應用,永遠都是目前顯示的fragment的執行個體。在Activity中執行onBackPressed時,總是執行的是,目前顯示的fragment的中的onBackPressed。

進過上面一個來回,我們拿到了fragment的執行個體,然後,在Activity的onBackPressed方法中通過判斷fragment中的onBackPressed方法傳回的boolean值做相應的邏輯處理。

這裡還存在一個問題,就是,當有多個Fragment時,我們在Activity中setSelectedFragment這個方法就需要改進。

@Override
        public void setSelectedFragment(PlaceholderFragment selectedFragment) {
            this.mPlaceholderFragment = selectedFragment;
        }
           
現在進行改進:如下建立一個接口BackFragmentInterFace。
package com.lemeng.weishi.interfaces;

public interface BackFragmentInterFace {

    public boolean onBackPressed();
}
           

然後我們的要實作傳回鍵的Fragment實作這個接口

這樣寫有什麼好處?

我們每個Activity中有很多個fragment,我們如果通過不斷地判斷目前顯示的是哪個fragment,然後再去做相應的邏輯處理,就會變麻煩。

會産生如下繁瑣的判斷邏輯(以下代碼可以看出,要進行大量的判斷顯示隐藏,然後做出相應的處理邏輯相對繁瑣複雜):

@Override
    public void onBackPressed() {
        if (getFragmentManager().findFragmentByTag("loginfragment") != null
                && getFragmentManager().findFragmentByTag("loginfragment")
                        .isVisible()) {
            finish();
            return;
        } else if (getFragmentManager().findFragmentByTag("registfragment") != null
                && getFragmentManager().findFragmentByTag("registfragment")
                        .isVisible()) {
            getFragmentManager().popBackStack();

        } else if (getFragmentManager().findFragmentByTag("resetfragment") != null
                && getFragmentManager().findFragmentByTag("resetfragment")
                        .isVisible()) {
            getFragmentManager().popBackStack();

        }
    }
           

通過比較,大家應該發現這種在fragment中監聽傳回鍵的方式的優雅之處了。