android tab切换的资源回收解决方案

现在大多数app都使用tab结构,2.3的时代主要使用tabhost去实现tab切换。但现在Android官方却不推荐直接使用tabhost类了,取而代之的是结合Fragment的FragmentTabHost.本人在工作中遇到了FragmentTabHost的优化工作,主要是tab切换时资源的回收问题,在翻查一些源码后有了以下的解决方案和总结。
       需要优化的起因:应用中有多个由fragment组成的tab,在切换的过程中,其他fragment的资源不释放,如果页面层级较深,或其他fragment
占用资源过多,容易导致oom。有一种极端的方法是切换以后就回收掉,这个导致的问题是下一次切换要完全初始化,导致切换速度变慢,有没有方法介于两者之间,使得在资源紧张时回收其他fragment,但是正常情况下保留其他fragment以保证切换的快速响应?

      首先要去了解FragmnetTabHost在切换过程中的逻辑,源码中我们找到了dotabchange方法,这里处理了tab切换时的fragment问题。


概括来讲,FragmnetTabHost使用了tabinfo内部类去记录已添加的tab即fragment,切换时判断将要切换的tabinfo和原有的tabinfo是否不同,如果  不同则detach原有的tabinfo对应的fragment,新的tabinfo如果没有fragment则初始化一个fragment然后attach该fragment, 有fragment则  直接attach。attach和detach又做了什么呢?这部分的源码在FragmentManager中,虽然提交是由FragmentTransaction做 的,但是那只是对事务的封装,最后的逻辑是在FragmentManager中。而FragmentManager中有两个list,一个记录actived状态的fragment,一个记录added状态的fragment。如下图(注:FragmentMannagerImpl是FragmentManagerde 具体实现类

detach完成的逻辑是将Fragment从added list中清除出去,将状态置为create(初始状态)然后调用moveToState去保证生命周期方法的回调,主要是ondestroyview attach则相反,将Fragment添加  到added list中,再使用  moveToState去完成  初始化的生命周期的回调,包括oncreate、oncreateView、onViewCreated。这里我们注意到即使detach后,fragment 也不会被回收,因为actived里面还有fragment的引用。也就是说detach虽然销毁了fragment里面的view,但是没有销毁fragment,这样下一
次attach时又需要重新oncreateview,但不会重新实例化fragment。从某种程度上这个时间也对切换tab有一定的影响。
有一种更加优化切换时间的方法,就是改变attach和detach方式为show和hide,   这样只会使用setvisable方法去切换,不会触发fragment 的生命周期,这样的好处是切换更快,但是占用内存也会更多,因为detach会销毁view,而hide不会。但是 如果使用show和hide不仅没有解决之前的内存紧张问题,反而略微加重了内存问题,使用空间换取了一点时间。那有没有办法在合适的 
时机回收掉不展示的fragment呢。如果可以重写FragmentManager,那么可以使用软引用去保存actived list,这样还是使用attach和detach,内存紧张时可以回收掉fragment的引用,但是FragmentManager涉及一些系统类,不方便重写。
综合以上,我们采取这样的策略去达到最初的目的:
  1. 首先使用show和hide方式,这样切换可以达到最快(正常情况很多使用viewPager的时候会默认加载三个fragment,前一个 当前和后一个,而通过实际项目经验我们知道这种情况下应用一启动就OOM的情况很少见,可见应用内存在应付主页时还是比较富裕的。因此使用show和hide虽然增加了部分内存,只要tab数目不要过多还是不太容易触发OOM的,而切换速度会比较迅速且不会反复刷新页面)
  2. 然后在点击某个tab中的控件触发跳转到二级页面即一个新的activity后触发保存其他tab的状态(启动一个延时5秒的runable,防止误操作或快速点击返回时回收页面)
  3. 回收其他tab,使用remove(fragment),remove以后fragment处于可回收的状态,调用GC可以显示的回收fragment
  4. 返回到原activity后判断是否保存了状态,若有则使用保存的状态去还原其他的tab并加载进来,但是默认的状态是hide
具体的实现是在activity中写两个runnable,一个用于保存状态,一个用于恢复状态,代码如下:


在activity中的onstop和onresume方法中去post对应的runnable就行了,需要注意的是处理activity退出时应该remove掉restorerunnable。
总结:这种方式会一定程度的增加程序的复杂度,如果除了主页tab数据较多,其他tab都较轻量级且不会有需要耗大量内存的子页面时候不宜采用这种方式。fragment的saveinstance会在fragmentmannager尝试保存信息时被调用,可以在onsaveinstance中保存列表滑动的信息等然后在oncreateview中去读取。

ps:第一次写,大神轻喷。如有错误,欢迎指正 微笑


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值