Fragment管理

上图的布局,大神立马就能看出来,最外面一个Activity,底下首页,分类,购物车..是第一层一个FragmentTabHost,而首页里面的类别01,02....是用的开源库TabPageIndicator管理的ViewPager,管理这第二层的n个Fragment。

1.当遇到这种嵌套多层的Fragment的时候第一个主要点就是第一层的FragmentManager,可以通过getSupportFragmentManager()或者getFragmentManager()获得,但是在 第二层的fragment中如果想获得FragmentManager就不能这样了,必须用getChildFragmentManager()。

2.当点击一个其中一个商品的详情的时候,如果想保持底部的TabHost那就不能用Activity,还得保持Fragment,其实还有另一中方案,那就是最外面的Activity用TabHostActivity,为什么没用尼,因为TabHostActivity已经被废弃了,当我看到那条废弃的横线时,就好像看到一个美女脸上被刀开花了一样,心痛啊,不能娶这样的媳妇啊,直接换FragmentTabHost,黄花大闺女,唉呀妈呀,老装逼了。回到需求,当点击其中一个商品时候,要将底部的TabHost保持,上面的布局都换成详情的布局,看下Api, FragmentTransaction 提供add,replace俩个方法,那么用add还是replace尼? 使用add()加入fragment时将触发onAttach(),使用attach()不会触发onAttach(), 使用replace()替换后会将之前的fragment的view从viewtree中删除。

触发顺序:
detach()->onPause()->onStop()->onDestroyView()
attach()->onCreateView()->onActivityCreated()->onStart()->onResume()
使用hide()方法只是隐藏了fragment的view并没有将view从viewtree中删除,随后可用show()方法将view设置为显示
而使用detach()会将view从viewtree中删除,和remove()不同,此时fragment的状态依然保持着,在使用attach()时会再次调用onCreateView()来重绘视图,注意使用detach()后fragment.isAdded()方法将返回false,在使用attach()还原fragment后isAdded()会依然返回false(需要再次确认)
执行detach()和replace()后要还原视图的话, 可以在相应的fragment中保持相应的view,并在onCreateView()方法中通过view的parent的removeView()方法将view和parent的关联删除后返回。

3.在复杂的Fragment管理中,经常会遇到 Fragment already added 错误,解决这样的错误方法就是,每次添加Fragment,先findFragmentByTag,如果找到了fragment.isAdded(),那么就return,跳出,如果Fragment没在栈中,那就把Fragment Add上去,下面放出一个Fragment管理的公用类

/**
   * Fragment跳转
   * @param fm
   * @param fragmentClass
   * @param tag
   * @param args
   */
  public void turnToFragment(FragmentManager fm, Class<? extends Fragment> fragmentClass, String tag, Bundle args) {
    mIsCanEixt = false;
    Fragment fragment = fm.findFragmentByTag(tag);
    boolean isFragmentExist = true;
    if (fragment == null) {
      try {
        isFragmentExist = false;
        fragment = fragmentClass.newInstance();
        fragment.setArguments(new Bundle());
      } catch (java.lang.InstantiationException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }
    }
    if(fragment.isAdded()){
      return;
    }
    if( args != null && !args.isEmpty() ) {
      fragment.getArguments().putAll(args);
    }
    FragmentTransaction ft = fm.beginTransaction();
    ft.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out,
        android.R.anim.fade_in, android.R.anim.fade_out);
    if( isFragmentExist ) {
      ft.replace(R.id.realtabcontent, fragment);
    } else {
      ft.replace(R.id.realtabcontent, fragment, tag);
    }
    
    ft.addToBackStack(tag);
    ft.commitAllowingStateLoss();
  }
最后为什么用
ft.commitAllowingStateLoss();
而不是

ft.commit();尼? commitAllowingStateLoss和commit的区别是当退出activity时,防止提交后的状态丢失。 对于你觉得可以丢失提交的状况,使用  commitAllowingStateLoss()

4.最后再介绍一种情况,还是上面的图,当在首页里面,进去了很多层,栈上面叠加了很多Fragment的时候,如果想再次点击TabHost的首页,能返回到最初首页的页面的话,那就要把首页的Fragment上面的Fragment的弹出,TabHost的再次点击事件:

mTabHost.getTabWidget().getChildAt(i)
          .setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                getSupportFragmentManager().popBackStack(null, 
                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
                mTabHost.setCurrentTab(j);
                mIsCanEixt = true;
            }
          });
解释一下:
getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
google提供了几种弹出栈的方法:
public abstract void  popBackStack   ()

Added in  API level 11

Pop the top state off the back stack. This function is asynchronous -- it enqueues the request to pop, but the action will not be performed until the application returns to its event loop.

public abstract void  popBackStack   ( String  name, int flags)
public abstract void  popBackStack   (int id, int flags)
public abstract boolean  popBackStackImmediate   (int id, int flags)

popBackStack(),配套使用的是ft.addToBackStack(tag);能在按返回键的时候,返回上一个fragment
popBackStack   ( String  name, int flags),如果name不为空,那么在这个Fragment上面的Fragment都会被弹出
flags Either 0 or  POP_BACK_STACK_INCLUSIVE .
0是不包括自己, POP_BACK_STACK_INCLUSIVE .
   

5.最最后,再加一个Fragment问题的解决,当Fragment的栈里面有几个fragment的时候,会出现,当你触摸当前fragment的时候,下层的fragment的事件被触发,这是由于Touch事件泄露传到了下层中。解决方法就是拦截onTouch事件

// 将上层的触摸事件拦截
  @Override
  public boolean onTouch(View v, MotionEvent event) {
    return true;
  }
在onViewCreated里面设置监听
@Override
  public void onViewCreated(View view, Bundle savedInstanceState) {
    // 拦截触摸事件,防止泄露下去
    view.setOnTouchListener(this);
    App.showLog(this.getClass().getSimpleName() + "  onViewCreated()");
    super.onViewCreated(view, savedInstanceState);
  }

google推出Fragment是为了适配平板,也方便开发者更灵活的布局,实现更多的交互效果,这次项目,还没有将Fragment的特性都掌握,看api的时候还是不能领会老外的想法,如果我要是老外的时候,看api就像看电视机的说明书一样,那多爽啊,因为api里面还有那么多方法没用过,但是我相信那些方法都是合理存在的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值