前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Fragment 基础知识

Fragment 基础知识

作者头像
Yif
发布2019-12-26 15:00:43
5490
发布2019-12-26 15:00:43
举报
文章被收录于专栏:Android 进阶Android 进阶
undefined
undefined

Fragment 生命周期

Fragment生命周期图

img
img

Fragment与Activity生命周期对比图

img
img
  1. 当一个fragment被创建的时候,它会经历以下状态.
    • onAttach()
    • onCreate()
    • onCreateView()
    • onActivityCreated()
  2. 当这个fragment对用户可见的时候,它会经历以下状态。
  • onStart()
  • onResume()
  1. 当这个fragment进入“后台模式”的时候,它会经历以下状态。
  • onPause()
  • onStop()
  1. 当这个fragment被销毁了(或者持有它的activity被销毁了),它会经历以下状态。
  • onPause()
  • onStop()
  • onDestroyView()
  • onDestroy()
  • onDetach()
  1. 在以下的状态中,可以使用Bundle对象保存一个fragment的对象。
  • onCreate()
  • onCreateView()
  • onActivityCreated()
  1. fragment新的状态。
  • onAttached() —— 当fragment被加入到activity时调用(在这个方法中可以获得所在的activity
  • onCreateView() —— 当activity要得到fragmentlayout时,调用此方法,fragment在其中创建自己的layout
  • onActivityCreated() —— 当activityonCreated()方法返回后调用此方法
  • onDestroyView() —— 当fragment中的视图被移除的时候,调用这个方法
  • onDetach() —— 当fragmentactivity分离的时候,调用这个方法

一旦activity进入resumed状态(也就是running状态),可以自由地添加和删除fragment了。因此,只有当activityresumed状态时,fragment的生命周期才能独立的运转,其它时候是依赖于activity的生命周期变化的。

FragmentonActivityCreatedonViewCreated调用顺序是 onViewCreated要优先于onActivityCreated调用

比如: 直接使用ViewPager实现嵌套的Fragment会让进入Activity中,所有的Fragment都加载完毕,数据都加载好,所有此时可以使用懒加载,切换到哪个Fragment就加载哪个Fragment,这个方式加载不同Fragment不好。最好的是使用一个Fragment,通过replace替换不同Fragment或者通过先将最新的Fragment add,再hide上一个Fragment,最后展示这个Fragment

Fragment中add、remove、replace区别

首先获取FragmentTransaction对象:FragmentTransaction transaction = getFragmentManager().beginTransaction();

两种方法不同之处:是否要清空容器再添加fragment的区别,用法上add配合hide或是remove使用,replace一般单独出现。

添加 add

一般会配合hide使用:transaction.add(R.id.fragment_container, oneFragment).hide(twoFragment).commit()

  1. 第一个参数是容器id, 第二个参数是要添加的fragment,添加不会清空容器中的内容,不停的往里面添加
  2. 不允许添加同一个fragment实例,这是非常重要的特点。如果一个fragment已经进来的话,再次添加的话会报异常错误的
  3. 添加进来的fragment都是可见的(visible),后添加的fragment会展示在先添加的fragment上面,在绘制界面的时候会绘制所有可见的view
  4. 所以大多数add都是和hide或者是remove同时使用的。这样可以节省绘制界面的时间,节省内存消耗,是推荐的用法

替换 replace

transaction.replace(R.id.fragment_container, oneFragment).commit()

  1. 替换会把容器中的所有内容全都替换掉,有一些app会使用这样的做法,保持只有一个fragment在显示,减少了界面的层级关系。
  2. 相同之处:每次addreplace都要走一遍fragment 的周期。

处理方式:

  1. 首先在add的时候,加上一个tab参数 `transaction.add(R.id.content, ContentFragment,"tag");
  2. 然后当ContentFragment引用被回收置空的话,先通过 ContentFragment=FragmentManager.findFragmentByTag("tag"); 找到对应的引用,然后继续上面的hide,show来处理;

在实战中的运用方法:

  • 如果我们使用replace来切换页面,那么在每次切换的时候,Fragment都会重新实例化,重新加载一边数据,这样非常消耗性能和用户的数据流量。
    • 这是因为replace操作,每次都会把container中的现有的fragment实例清空,然后再把指定的fragment添加进去,就就造成了在切换到以前的fragment时,就会重新实例会fragment

正确的切换方式是add(),切换时hide()add()另一个Fragment;再次切换时,只需hide()当前,show()另一个。

使用:

代码语言:javascript
复制
public void addFragment(Fragment from, Fragment to) {
        if (!to.isAdded()) { // 先判断是否被add过
             transaction.hide(from).add(R.id.content_frame, to).commit(); // 隐藏当前的fragment,add下一个到Activity中
 
            } else {
                transaction.hide(from).show(to).commit(); // 隐藏当前的fragment,显示下一个
        }

FragmentTransaction

FragmentTransaction事务回滚使用方法:

transaction.commit()之前,使用addToBackStack()将其添加到回退栈中。

transaction.addToBackStack(String tag);

在需要回退时,使用popBackStack()将最上层的操作弹出回退栈。

manager.popBackStack();

这里的popBackStack()是弹出默认的最上层的栈顶内容。

当栈中有多层时,我们可以根据id或TAG标识来指定弹出到的操作所在层。函数如下:

代码语言:javascript
复制
void popBackStack(int id, int flags);
void popBackStack(String name, int flags);

其中:

  • 参数int id是当提交变更时transaction.commit()的返回值。
  • 参数string nametransaction.addToBackStack(String tag)中的tag值;
  • int flags有两个取值:0或FragmentManager.POP_BACK_STACK_INCLUSIVE
    • 当取值0时,表示除了参数一指定这一层之上的所有层都退出栈,指定的这一层为栈顶层;
    • 当取值POP_BACK_STACK_INCLUSIVE时,表示连着参数一指定的这一层一起退出栈;

detach与attach区别

detach

detach():会将viewfragment分离,将此将viewviewtree中删除,而且将fragmentActivityADD队列中移除,所以在使用detach()后,使用fragment::isAdded()返回的值是false;但此fragment实例并不会删除,此fragment的状态依然保持着使用,所以在fragmentManager中仍然可以找到,即通过FragmentManager::findViewByTag()仍然是会有值的。

attach

attach():显然这个方法与detach()所做的工作相反,它一方面利用fragmentonCreateView()来重建视图,一方面将此fragment添加到ADD队列中;这里最值得注意的地方在这里:由于是将fragment添加到ADD队列,所以只能添加到列队头部,所以attach()操作的结果是,最新操作的页面始终显示在最前面,由于这里会将fragment添加到ActivityADD队列中,所以在这里调用fragment::isAdded()将返回True;

系统BUG——add()replace()不能一起使用

Fragment commit 和 commitAllowingStateLoss 的区别

如果activity的状态被保存了,这里再提交就会检查这个状态,符合条件就抛出一个异常来终止应用进程。也就是说在activity调用了onSaveInstanceState()之后,再commit一个事务就会出现该异常。那如果不想抛出异常,也可以很简单调用commitAllowingStateLoss()方法来略过这个检查就可以了,但是Google说这是危险的,在官方文档上有如下描述:

Like {@link #commit} but allows the commit to be executed after an activity’s state is saved. This is dangerous because the commit can be lost if the activity needs to later be restored from its state, so this should only be used for cases where it is okay for the UI state to change unexpectedly on the user.

意思是如果activity随后需要从它保存的状态中恢复,这个commit是会丢失的。因此它仅仅适用在ui状态的改变对用户来说是可以接受的。

结论:

  1. activity的生命周期方法中提交事务要小心,越早越好,比如onCreate。也可以在接收用户的输入时来提交。尽量避免在onActivityResult()方法中提交。
  2. 避免在异步的回调方法中执行commit。因为他们感知不到当前activity生命周期的状态。
  3. 使用commitAllowingStateLoss()代替commit()。相比于crash,ui状态的改变对用户来说是可以接受的。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年7月18日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Fragment 生命周期
    • Fragment生命周期图
      • Fragment与Activity生命周期对比图
      • Fragment中add、remove、replace区别
        • 添加 add
          • 替换 replace
          • FragmentTransaction
          • detach与attach区别
            • detach
              • attach
              • Fragment commit 和 commitAllowingStateLoss 的区别
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档