专栏名称: 郭霖
Android技术分享平台,每天都有优质技术文章推送。你还可以向公众号投稿,将自己总结的技术心得分享给大家。
目录
相关文章推荐
开发者全社区  ·  公务员性价比正在消失 ·  11 小时前  
开发者全社区  ·  字节员工:蚂蚁金服是开闸放水吗?认识好几个很 ... ·  14 小时前  
开发者全社区  ·  突然崩了!很多人以为手机坏了!官方紧急回应 ·  昨天  
开发者全社区  ·  蔚来多部门裁员,裁减10%-50%,20分钟完成 ·  2 天前  
51好读  ›  专栏  ›  郭霖

死磕Fragment的生命周期

郭霖  · 公众号  · android  · 2017-01-09 08:00

正文

今日科技快讯

近日,由国家网信办起草的《未成年人网络保护条例(送审稿)》获得披露。该条例亮点颇多,比如智能手机在出厂时预装未成年人上网保护软件,可能将成为法律法规的明文要求;对未成年人实施网络欺凌,构成犯罪的,将被依法追究刑事责任;禁止未成年人在每日0到8点打网游。

作者简介

大家早上好,新的一周开始了!本篇是 MeloDev 的第三篇投稿,详细地介绍了他是如何管理Fragment的生命周期的,并且还有结合ViewPager的讲解。希望他的经验能够帮助到有需要的朋友。

MeloDev 的博客地址:

http://www.jianshu.com/u/f5909165c1e8

前言

本文例子中 github 地址,github BuzzerBeater 项目链接:

https://github.com/itsMelo/BuzzerBeater

第一个开源项目,目前在逐步更新一些知识点,希望对你有所帮助

曾经在北京拥挤的13号线地铁上,一名背着双肩包穿着格子衫带着鸭舌帽脚踏帆布鞋的程序员讲了一句:“我觉得 Fragment 真的太难用了”。从而引起一阵躁动激烈的讨论。

正方观点:

Fragment 真的太好用了。要知道因为 Activity 的启动,涉及到 Android 系统对 ActivityManager 的调度,会关联许多资源和进行诸多复杂运算,在一些高端手机上,这个调度的时长甚至会超过 100 ms。反观 Fragment,启动如巧克力入口般顺滑,轻量不消耗手机资源。还可以做成一个个模块,方便 Activity 复用。并且如果要涉及平板的适配,Fragment 更是必不可少。

反方观点:

Fragment 难用,属于坑多难填。Fragment 本质上是一个有生命周期的 View,生命周期繁多并且异常难管理,多个 Fragment 嵌套更是坑中之坑(我也遇到过...),连 square 和 FaceBook 都摒弃了 Fragment,更何况我们呢!

好吧,不要吵了,用或者不用,遇到问题如何解决,相信大家心里都有一个自己的答案。结合我自己开发时候遇到的问题,下面我们来总结一下 Fragment 的生命周期管理方式,以及一些技巧和建议。

hide & show

先结合一张项目截图,来直观地看看目前我是如何管理 Fragment 的。

因为我们的项目架构是一 Activity 多 Fragment,并且把所有的 Fragment 都装载到了一个 ViewPager 里面,启动一个新的 Fragment 的过程也是 ViewPager 滑动翻页的过程,未来会考虑把这种管理方式总结成文,整理给大家。总之你目前看到的上图界面,都是 Fragment 呈现的,并且点击按钮什么的,也会跳转到下一个 Fragment,这就涉及到了 Fragment 嵌套。

我也写了一个 Demo,去模拟了这个页面的搭建。这里想多说几句:

通过点击下方 Tab 管理页面的方式目前非常主流,这种布局方式事实上是从 iOS 上面借鉴过来的。(反正现在两大系统都是相互学习)在前一阵 google 的 support 25 包也终于推出了官方的 BottomNavigationView ,不过我的 Android Studio 安装 support 25 总是失败,所以在项目中我选用了一个还不错的开源库来做下方的底部导航。

BottomNavigationView 本身有一套 Material Design 的设计规范如下:

Material Design Navigation Bottom

https://material.google.com/components/bottom-navigation.html

感兴趣的去阅读一下,以后对产品、设计开撕是很有帮助的。其中有这么一条很有意思,是说 BottomNavigationView 并不建议把它设计成横向滑动的形式,也就是用 ViewPager 去装载 Fragment。为什么说这句很有意思呢?事实上市面上很多主流的 app,它们的 BottomNavigationView 确实是不可以横向滑动的,而我们每个人都在用的,月活8亿的国民软件微信,就恰恰把它的主页面做成了可以横向滑动的。

这里我想说下我的个人看法,首先规范未必需要严格遵守,做什么样的功能实现什么样的效果,要结合自己项目的架构和产品做一个合理的需求。拿 360手机助手 这个 app 举例,它底部的每一个 tab 都搭建了一个非常“重量级”的模块,并且每个 tab 下界面的内部还有许多负责的 View 层级和嵌套滑动的 ViewPager,所以试想一下,这样的页面要是做成微信那个样子,不卡顿就怪了~反观微信,首先我认为它的每个界面层级和交互都不复杂,逻辑也都在页面内,所以做成横向滑动的反而能提升用户的体验。

好了,前面说了好多无关紧要的话,赶紧来看看 demo 中通过 hide 和 show 的方式如何来管理 Fragment。

MainActivity


代码理解起来非常容易,我通过 add & show / hide 的方式来管理底部的四个 tab 相互切换,并且打印了这四个 Fragment 的所有生命周期方法,包括 onHiddenChanged setUserVisibleHint

当第一次进入某个页面时:

可以看到,当我依次点击下方四个 tab,界面第一次加载的时,会走 Fragment 的创建周期 onAttach -- onResume,也许你会问,上面我执行相互切换操作,从第一个页面切换到第二个的时候,为什么第一个 Fragment 页面不可见了,不会调用 onPause 和 onStop 呢?

这是在你了解过 Activity 生命周期并且刚接触 Fragment 的生命周期时,第一个容易陷入的误区,事实上 Fragment 的生命周期,除了第一次它创建或销毁之外,统统都是由 Activity 所驱动的。 举个例子,当我点击 home 键回到桌面时:

可以看到我已经加载了的几个 Fragment 齐刷刷的调用了 onPause 和 onStop,如此得步调一致是因为这些 Fragment attach 的 Activity 回调了 onPause 和 onStop。相信肯定会有人说“不对啊,我要是用 replace 的方式去切换 Fragment,我打包票 Fragment 会像 Activity 一样,完整得走完生命周期“

你说的没错,因为 replace 这种切换方式就是始终上面我总结的那句“首次创建或销毁“,并且在 BottomNavigation 这样的使用场景中,没人会用这种 replace 的方式,因为每次切换都要重新创建 Fragment,用户看了下流量估计会打 12315 了。

(如果 Fragment 代表前男/女友,据说男人是用 add 保存,女人使用 replace 替换 hhh...)

当底部的四个 Fragment 都已经加载完成之后咧?再一起看下 log:

onHiddenChanged 回调

当底部四个 Fragment 全部创建入栈之后,show 和 hide 来管理 Fragment,此时只有 onHiddenChanged 方法回调,这时候显然你可以在 hide = false 时,做一些资源回收操作,在 hide = true 时,做一些刷新操作。

在刚才我们打印的方法中,好像有一个一直没出现,没错就是 setUserVisibleHint ,如果你做过 Fragment+ViewPager 的懒加载(下文我们会讲这个),相信你对它就比较熟悉了,通过名字就能猜测出来,这个方法是我们主动设置给 Fragment 的,那我们就来试试看:

改造 a ddOrShowFragment


在切换时,我们对上一个 fragment setUserVisibleHint 设置为 false ,要展现的 Fragment setUserVisibleHint 设置为 true ,打印 log 看看:

可以看到目前我们用 setUserVisibleHint 也达到了与 onHiddenChanged 一样的效果。

文章写到现在,我们来做一个总结,上文的这种方式就是主流通过 BottomNavigation 管理 Fragment 的方式,这种方式有什么好处呢?毫无疑问会节省资源,不点开的界面不去创建它(这一点 ViewPager 做不到),只创建一次,未来仅仅更新界面数据就可以了。







请到「今天看啥」查看全文