關于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中監聽傳回鍵的方式的優雅之處了。