关于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=1;
@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>3;
}
}
在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中监听返回键的方式的优雅之处了。