fragment那点事

前言:

先来介绍一个专业术语:

"内存重启":“术语”,安卓app有一种特殊情况,就是 app运行在后台的时候,系统资源紧张的时候导致把app的资源全部回收(杀死app的进程),这时把app再从后台返回到前台时,app会重启。这种情况下文简称为:“内存重启”。(屏幕旋转等配置变化也会造成当前Activity重启,本质与“内存重启”类似)
        在系统要把app回收之前,系统会把Activity的状态保存下来,Activity的FragmentManager负责把Activity中的Fragment保存起来。在“内存重启”后,Activity的恢复是从栈顶逐步恢复, Fragment会在宿主Activity的onCreate方法调用后紧接着恢复(从onAttach生命周期开始)。

activity 传递数据给fragment

       google推荐使用这种方式

一、创建对象:
    public static final FragmentListView newInstance(String string){
        FragmentListView fragmentListView = new FragmentListView();
        Bundle bundle = new Bundle();
        //将需要传递的字符串以键值对的形式传入bundle
        bundle.putString("data",data);
        fragmentListView.setArguments(bundle);
        return fragmentListView;
    }
二、设置传递的参数:
    @Override
    public void setArguments(Bundle args) {
        super.setArguments(args);
    }
三、获取传递进来的参数:
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle arguments = getArguments();

    }


 add(), show(), hide(), replace()的那点事


1、区别
    show(),hide()最终是让Fragment的View setVisibility(true还是false),不会调用生命周期;
    replace()的话会销毁视图,即调用onDestoryView、onCreateView等一系列生命周期;
    add()和 replace()不要在同一个阶级的FragmentManager里混搭使用。
2、使用场景
    如果你有一个很高的概率会再次使用当前的Fragment,建议使用show(),hide(),可以提高性能。
    在我使用Fragment过程中,大部分情况下都是用show(),hide(),而不是replace()。
    注意:如果你的app有大量图片,这时更好的方式可能是replace,配合你的图片框架在Fragment视图销毁时,回收其图片所占的内存。



块Activity+多Fragment的架构?

单Activity+多Fragment:
    一个app仅有一个Activity,界面皆是Frament,Activity作为app容器使用。
    优点:性能高,速度最快。参考:新版知乎 、google系app
    缺点:逻辑比较复杂,尤其当Fragment之间联动较多或者嵌套较深时,比较复杂。

多模块Activity+多Fragment:
    一个模块用一个Activity,比如
    1、登录注册流程:
        LoginActivity + 登录Fragment + 注册Fragment + 填写信息Fragment + 忘记密码Fragment
    2、或者常见的数据展示流程:
        DataActivity + 数据列表Fragment + 数据详情Fragment + ...
    优点:速度快,相比较单Activity+多Fragment,更易维护。

    权衡利弊,我认为多模块Activity+多Fragment是最合适的架构,开发起来不是很复杂,app的性能又很高效。
    当然。Fragment只是官方提供的灵活组件,请优先遵从你的项目设计!真的特别复杂的界面,或者单个Activity就可以完成一个流程的界面,使用Activity可能是更好的方案。


activity与fragment常用的交互的方式:

1. handler:在fragment里面创建handler,再利用activity对象将这个handler对象设置到activity里面

2. brodcast:在activity里面注册广播,在Brodcast里面发送

3. 接口回调:在Brodcast里面创建接口,在activity实现这个接口

4. 下面提到的getSupportFragmentManager().findFragmentByTag()和getSupportFragmentManager().getFragments()

getActivity()空指针问题

不要在fragment里面直接使用getActivity(),用下面代码代替:
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        activity = (MainActivity) context;
    }


Fragment重叠异常-----正确使用hide、show的姿势:

            如果你add()了几个Fragment,使用show()、hide()方法控制,比如微信、QQ的底部tab等情景,如果你什么都不做的话,在“内存重启”后回到前台,app的这几个Fragment界面会重叠。
        原因是FragmentManager帮我们管理Fragment,当发生“内存重启”,他会从栈底向栈顶的顺序一次性恢复Fragment;
        但是因为没有保存Fragment的mHidden属性,默认为false,即show状态,所以所有Fragment都是以show的形式恢复,我们看到了界面重叠。
        (如果是replace,恢复形式和Activity一致,只有当你pop之后上一个Fragment才开始重新恢复,所有使用replace不会造成重叠现象)
            还有一种场景,add和replace都有可能造成重叠: 在onCreate中加载Fragment,并且没有判断saveInstanceState==null,导致重复加载了同一个Fragment导致重叠。(PS:replace情况下,如果没有加入回退栈,
        则不判断也不会造成重叠,但建议还是统一判断下)

方法一:根据tag来判断

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity);

        TargetFragment targetFragment;
        HideFragment hideFragment;

        if (savedInstanceState != null) {  // “内存重启”时调用
            targetFragment = getSupportFragmentManager().findFragmentByTag(TargetFragment.class.getName);
            hideFragment = getSupportFragmentManager().findFragmentByTag(HideFragment.class.getName);
            // 解决重叠问题
            getFragmentManager().beginTransaction()
                    .show(targetFragment)
                    .hide(hideFragment)
                    .commit();
        }else{  // 正常时
            targetFragment = TargetFragment.newInstance();
            hideFragment = HideFragment.newInstance();

            getFragmentManager().beginTransaction()
                    .add(R.id.container, targetFragment, targetFragment.getClass().getName())
                    .add(R.id,container,hideFragment,hideFragment.getClass().getName())
                    .hide(hideFragment)
                    .commit();
        }
    }
    如果你想恢复到用户离开时的那个Fragment的界面,你还需要在onSaveInstanceState(Bundle outState)里保存离开时的那个可见的tag或下标,在onCreate“内存重启”代码块中,取出tag/下标,进行恢复。
    
    

方式二:通过getFragments()可以获取到当前FragmentManager管理的栈内所有Fragment。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity);

        TargetFragment targetFragment;
        HideFragment hideFragment;

        if (savedInstanceState != null) {  // “内存重启”时调用
            List<Fragment> fragmentList = getSupportFragmentManager().getFragments();
            for (Fragment fragment : fragmentList) {
                if(fragment instanceof TartgetFragment){
                   targetFragment = (TargetFragment)fragment;
                }else if(fragment instanceof HideFragment){
                   hideFragment = (HideFragment)fragment;
                }
            }
            // 解决重叠问题
            getFragmentManager().beginTransaction()
                    .show(targetFragment)
                    .hide(hideFragment)
                    .commit();
        }else{  // 正常时
            targetFragment = TargetFragment.newInstance();
            hideFragment = HideFragment.newInstance();

            // 这里add时,tag可传可不传
            getFragmentManager().beginTransaction()
                    .add(R.id.container)
                    .add(R.id,container,hideFragment)
                    .hide(hideFragment)
                    .commit();
        }
    }




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值