一、概述
在一个Activity+多个Fragment的回退处理,一开始使用传统的add加hide,show进行判断切换,这样对于同级fragment用着挺不错的,比如导航栏类似的功能,多个层级的回退就需要添加判断很不实用,所以用到了addToBackStack,popBackStack来实现。还有就是自己定义一个list来管理fragment,这个可以参考文章。
hide和show的导航栏:
private void hideAllFragment(FragmentTransaction fTransaction)
{
if (detailFragment!=null)fTransaction.hide(detailFragment);
if (listFragment!=null)fTransaction.hide(listFragment);
if (searchFragment!=null)fTransaction.hide(searchFragment);
}
public void openDetailFragment(int fragment_type){
FragmentTransaction fTransaction = fManager.beginTransaction();
//首先隐藏清单fragment
hideAllFragment(fTransaction);
//再显示详细fragment
switch (fragment_type) {
case KTVType.FragmentType.ROOMDETAIL:
if (detailFragment == null){
detailFragment=new HistoryOderdetailFragment();
fTransaction.add(R.id.setting_content, detailFragment);
}
else
fTransaction.show(detailFragment);
break;
case KTVType.FragmentType.PRODUCTDETAIL:
...
}
fTransaction.commit();
}
二、回退栈使用
具体生命的周期分析可以参考文章,重写onBackPressed 用于back回退和toolbar的回退配合使用()
private void initFragment(){
fManager = getSupportFragmentManager();
FragmentTransaction fTransaction = fManager.beginTransaction();
settingFragment = new SettingFragment();
fTransaction.add(R.id.setting_content, settingFragment);
// fTransaction.addToBackStack(null);
fTransaction.commit();
}
/**
* 打开对应的fragment
* @param fragment_type
*/
public void openFragment(int fragment_type)
{
FragmentTransaction fTransaction = fManager.beginTransaction();
switch (fragment_type) {
case KTVType.FragmentType.ROOMDETAIL:
if (roomDetailsFragment == null)
roomDetailsFragment = new RoomDetailsFragment(this);
fTransaction.replace(R.id.setting_content, roomDetailsFragment);
break;
case KTVType.FragmentType.PRODUCTDETAIL:
if (productDetailsFragment == null)
productDetailsFragment = new ProductDetailsFragment(this);
fTransaction.replace(R.id.setting_content, productDetailsFragment);
break;
case KTVType.FragmentType.ADDROOM:
if (addRoomFragment == null)
addRoomFragment = new AddRoomFragment();
fTransaction.replace(R.id.setting_content, addRoomFragment);
break;
case KTVType.FragmentType.ADDPRODUCT:
if (addProductFragment == null)
addProductFragment = new AddProductFragment(this);
fTransaction.replace(R.id.setting_content, addProductFragment);
break;
default:
}
fTransaction.addToBackStack(null);
fTransaction.commit();
}
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() <= 0)//这里是取出我们返回栈存在Fragment的个数
finish();
else
getSupportFragmentManager().popBackStack();
}
replace,add看需求使用:我这里是需要每次都是刷新的,所以采用replace,
- replace方法添加新的Fragment在回退的时候Fragment会重新加载,
- add 配合 hide使用,能保存fragment状态不会每次刷新视图。
注意:add配合hide不能使用上面的hideAllFragment这样会隐藏掉所有对象,再次add不会出现,所以在每次add的同时hide上一个。
eg: 代码不变,add代替replace,同时添加hide,这样布局就不会重新加载相当于hide和show。
private void initFragment(){
...
fTransaction.add(R.id.setting_content, settingFragment, 0+"");
...
}
public void openFragment(int fragment_type){
...
fTransaction.add(R.id.setting_content, roomDetailsFragment,1+"");
...
fTransaction.add(R.id.setting_content, productDetailsFragment,2+""));
...
fTransaction.addToBackStack(null);
fTransaction.hide(fManager.findFragmentByTag(0+""));
fTransaction.commit();
}
注意:当Fragment被另一个Fragment replace(), 并且压入back stack中, 此时它的View是被销毁的, 但是它本身并没有被销毁.
也即, 它走到了onDestroyView(), 却没有走onDestroy()和onDetact()。等back回来的时候, 它的view会被重建, 重新从nCreateView()开始走生命周期。在这整个过程中, 该Fragment中的成员变量是保持不变的, 只有View会被重新创建.
在这个过程中, instance state的saving并没有发生。
public class TransactionActivity extends BaseActivity {
//定义三种fragment类型
private FragmentManager fManager;//获取管理器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_transaction);
hideStatusBar();
inirFragment();
}
private void inirFragment(){
fManager = getSupportFragmentManager();
FragmentTransaction fTransaction = fManager.beginTransaction();
fTransaction.add(R.id.history_fragment_content, new HistoryOrderlistFragment());
//fTransaction.addToBackStack(null);//会出现空白页
fTransaction.commit();
}
/**
* 打开对应的fragment
*/
public void openFragment(@Nullable KTVOrderInfo orderInfo)
{
BaseFragment baseFragment = null;
FragmentTransaction fTransaction = fManager.beginTransaction();
if (orderInfo!=null)
fTransaction.replace(R.id.history_fragment_content, new HistoryOderdetailFragment(orderInfo));
else
fTransaction.replace(R.id.history_fragment_content, new SearchFragment());
fTransaction.addToBackStack(null);
fTransaction.commit();
}
@Override
public void basefinish() {
if (getSupportFragmentManager().getBackStackEntryCount() <= 0)//这里是取出我们返回栈存在Fragment的个数
finish();
else
getSupportFragmentManager().popBackStack();
}
}
Notes:这种初始化的fragment使用add/replace,不要添加到addToBackStack里面,不然最后一下回退会出现空白页。
三、回退栈修改版
由于回退栈虽然销毁了视图但是实例还在,数据还在,再次加载的时候回到原来的状态,对于这次的项目不太适合,所以采用参考list控制的方式来控制。
//因为是replace是所以添加fragment的类型,如果hide,show可以使用List<BaseFragment>
private List<Integer> fragmentTypeList = new ArrayList<>();
/**
* 打开对应的fragment
* @param fragment_type
* @param isBack 是否是后退操作,用于判定动画方向
*/
public void openFragment(int fragment_type,boolean isBack)
{
BaseFragment baseFragment = null;
FragmentTransaction fTransaction = fManager.beginTransaction();
if (isBack)
fTransaction.setCustomAnimations(R.anim.slide_left_in,R.anim.slide_right_out);
else
fTransaction.setCustomAnimations(R.anim.slide_right_in,R.anim.slide_left_out);
switch (fragment_type) {
case KTVType.FragmentType.ROOMDETAIL:
baseFragment = new RoomDetailsFragment(this);
break;
case KTVType.FragmentType.PRODUCTDETAIL:
baseFragment = new ProductDetailsFragment(this);
break;
case KTVType.FragmentType.ADDROOM:
baseFragment = new AddRoomFragment();
isEditContent = true;
break;
case KTVType.FragmentType.ADDPRODUCT:
baseFragment = new AddProductFragment(this);
isEditContent = true;
break;
case KTVType.FragmentType.SETTING:
baseFragment = new SettingFragment();
break;
default:
}
fragmentTypeList.add(fragment_type);
fTransaction.replace(R.id.setting_content, baseFragment);
fTransaction.commit();
}
@Override
public void basefinish() {
if (fragmentTypeList.size() > 1) {
int temp = fragmentTypeList.get(fragmentTypeList.size()-2);
//连续去除集合后两位
fragmentTypeList.remove(fragmentTypeList.size()-1);
fragmentTypeList.remove(fragmentTypeList.size()-1);
openFragment(temp,true);
}else
finish();
}