一、概述

在一个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,

  1. replace方法添加新的Fragment在回退的时候Fragment会重新加载,
  2. 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();
      }