当我们需要切换fragment的时候,官方给我们提供了两种方式:replace和add.
首先来看看replace方法:
replace方法相当于先移除remove()原来所有已存在的fragments,然后添加add()当前这个fragment。这就导致了一个问题,我们切换一次,然后再切换回来,相当于重新加载了这个fragment,原来的状态不复存在,这显然与我们的日常使用不符。先做个实现说明一下这个现象。
最下面是两个按钮,用于切换两个Fragment,第一个Fragment中是一个按钮和一个文字,默认显示为你好吗,点击按钮切换文字为我很好,如图所示
但是当我们点击第二个按钮切换到第二个Fragment,然后在切换回来的时候,发现文字又变成默认的了,这就说明重新实例化了fragment对象,Fragment的状态没有得到保存。
我们在每个Fragment的生命周期的onCreateView方法中打印一行Log
Log.d("Fragment", "FragmentOne------onCreateView");
每次切换Fragment时我们去看控制台是不是都会打印这句话。
可以看到,每次点击按钮切换Fragment时都会调用Fragment的onCreateView生命周期方法。这就说明使用replace方法切换Fragment是无法保存状态的。
代码如下:
public class MainActivity extends FragmentActivity implements OnClickListener {
private Button bt1;
private Button bt2;
private FragmentManager manager;
private FragmentTransaction transaction;
FragmentOne fragmentOne;
FragmentTwo fragmentTwo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt1 = (Button) findViewById(R.id.bt1);
bt2 = (Button) findViewById(R.id.bt2);
bt1.setOnClickListener(this);
bt2.setOnClickListener(this);
manager = getSupportFragmentManager();
// 默认选中第一个按钮
bt1.performClick();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt1:
if (fragmentOne == null) {
fragmentOne = new FragmentOne();
}
transaction = manager.beginTransaction();
transaction.replace(R.id.fl_content, fragmentOne);
break;
case R.id.bt2:
if (fragmentTwo == null) {
fragmentTwo = new FragmentTwo();
}
transaction = manager.beginTransaction();
transaction.replace(R.id.fl_content, fragmentTwo);
break;
}
transaction.commit();
}
}
接下来看看add方法:
使用add的时候要和hide和show方法结合起来使用,使用hide隐藏原来的fragment,使用show显示你想要的fragment.
通过实验发现当第一个framgment里面的文字改变之后,在切换回来文字的状态依然是显示为我很好。而且通过控制台我们可以看到两个fragment的onCreateView方法只是在第一次点击按钮的时候会调用,下次切换不在调用。
说明采用add方法很好的保存的fragment的状态,避免每次去实例化新的对象。
代码如下:
public class MainActivity extends FragmentActivity implements OnClickListener{
private Button bt1;
private Button bt2;
//代表当前的fragment
private Fragment content;
FragmentOne fragmentOne;
FragmentTwo fragmentTwo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt1 = (Button) findViewById(R.id.bt1);
bt2 = (Button) findViewById(R.id.bt2);
bt1.setOnClickListener(this);
bt2.setOnClickListener(this);
content = new FragmentOne();
//默认选中第一个Fragment
bt1.performClick();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt1:
if(fragmentOne == null){
fragmentOne = new FragmentOne();
}
switchContent(content, fragmentOne);
break;
case R.id.bt2:
if(fragmentTwo == null){
fragmentTwo = new FragmentTwo();
}
switchContent(content, fragmentTwo);
break;
}
}
/**
* 切换fragment
* @param from 要隐藏的fragment
* @param to 要显示的fragment
*/
public void switchContent(Fragment from, Fragment to){
if(content!=to){
content =to;
FragmentTransaction transaction= getSupportFragmentManager().beginTransaction();
//此处必须要进行判断,因为同一个fragment只能被add一次,否则会发生异常
if(!to.isAdded()){
//未添加
transaction.hide(from).add(R.id.fl_content, to).commit();
}else{
//添加过直接显示
transaction.hide(from).show(to).commit();
}
}
}
}
但是,在使用add的时候,作为容器的FrameLayout其实有2层,使用replace的话只有一层,多层肯定比一层来的浪费。具体使用什么方法还是看具体的需求吧!