版权声明:缓存
本帐号发布文章均来自公众号,承香墨影(cxmyDev),版权归承香墨影全部。安全
未经容许,不得转载。网络
在 Android 系统中,当运行的 App 被移动到后台的以后,Android 为了保证下次启动的速度,会将它移入 Cached 的状态,这个时候实际上,该 App 的进程依然存在,可是对应的组件是否存在,就不必定了。而既然该 App 的进程还存活着,下次启动的速度就会很快,这就是常说的热启动。ide
可是这些被退出到后台的 App ,也并非彻底安全不会被清理掉的,他们可能只是没有持有任何的组件,而且是不占用 CPU 资源的,可是它依然会占据内存空间。而当系统认为内存不足的时候,就会按照优先级清理掉一些优先级不那么高的进程,来回收一些内存空间,供新启动的程序使用,这就是 LowMemoryKiller 的策略。性能
那么,为了让咱们的 App 在后台尽量活的久一点,无非就是将内存下降,从而使得优先级提升,而实现不被系统回收的功能(这是一个常规的优化方案,而非保活方案)。那么,若是咱们能明确当前 App 处于什么状态,就能在此时机,释放一些不须要持有的内存资源,来达到咱们的目的。优化
这个时候,就须要用到 onTrimMemory()
这个回调方法了。spa
前面提到,咱们能够经过实现 onTrimMemory()
方法,来完成对当前 App 在内存中的优先级的简单管理。3d
而 onTrimMemory()
回调方法,是 Android Level 14(Android 4.0) 以后提供的一个 API,它主要的做用是提醒开发者,在系统内存不足的时候,应该经过释放部分不重要的内存资源,从而避免被 Android 系统服务杀掉。code
能够看到,onTrimMemory()
本质上是一种告知 App 处于系统内存回收的不一样阶段的时机,应该在这些时机,合理对自身持有的内存进行释放,以免被系统直接杀掉,从而让保证下次用户启动 App 时候的速度。cdn
onTrimMemory()
的完整方法签名以下:
public void onTrimMemory(int level)复制代码
能够看到,它实际上,会有一个 level 参数来标记当前的 App 在内存中的级别,也就意味着 onTrimMemory()
方法,可能会被屡次调用到。
既然 onTrimMemory()
方法会传递一个 level 参数,那么就先来看看,各类 level 参数所表明的含义。
其实从 level 值的取名来看,大体能够分为三类:
这三类中,一般咱们只须要关心 App 被置于 Cached 状态下的状况,由于系统是不会杀掉一个正在前台运行的 App 的(但可能会触发 OOM),可是若是该 App 有一些后台服务正在运行,这个服务也是有被杀的风险的。
而在 Cached 状态下的时候,当收到 TRIM_MEMORY_Xxx 的回调,就须要注意了,这些只是标记了当前 App 处于 LRU List 的位置,也就是说,若是回收了靠前的 App 进程以后,依然达不到内存使用的要求,可能会进一步去杀进程,也就是说,极端状况下,可能从 TRIM_MEMORY_BACKGROUND 到 TRIM_MEMORY_COMPLETE 是瞬间完成的事情,因此咱们须要慎重处理它们,尽可能对这三个状态都进行判断,而后作统一的回收内存资源的处理。
既然说到了 onTrimMemory()
回掉,看样子它是和 App 相关的,因此最少在 Application 中,应该是能够对其进行重写来监听回调的。可是除了 Application,其余的一些组件中,也是能够监听它的。
这些能够监听 onTrimMemory 的组件有:
除了前面提到的系统默承认以监听 onTrimMemory()
的组件以外,咱们还能够自定义 onTrimMemory 的监听。
自定义起来也很是的简单,只须要实现 ComponentCallbacks2 接口,而后调用 Application.registerComponentCallbacks()
方法注册便可。
除了 registerComponentCallbacks()
方法进行注册监听以外,若是不使用了的话,还可使用 unregisterComponentCallbacks()
进行解注。
那么这里是如何实现的呢?让咱们来看看 Application 的对应源码。
能够看到,它其实是经过一个 mComponentCallbacks 的列表进行维护的。
而在 onTrimMemory()
的时候,又从 mComponentCallbacks 中获取到全部的 callbacks 对象,进行消息的分发。
经过这种方式实现了对 onTrimMemory()
的自定义监听。
而 onTrimMemory()
方法同时被标记为 @CallSuper,也就严格要求了重写它的子类,必须调用父类中的 onTrimMemory()
方法,从而保证了消息的分发不会缺失。
onTrimMemory()
既然是 Android 4.0 才新增长的 Api,那么对于低版本的设备而言,能够监听 onLowMemory()
方法,它大概能够等同于 level 级别为 TRIM_MEMORY_COMPLETE 的回调。
固然,ComponentCallbacks2 接口继承的 ComponentCallback 接口,也是须要实现 onLowMemory()
方法的。
Android 系统会在自身内存不足的状况下,清理掉一些不重要的进程来释放内存资源,以供优先级更高的进程使用。而这个顺序,主要是按照 LRU List 中的优先级来清理的,可是它也同时会考虑清理掉哪些占用内存较高的进程来让系统更快的释放跟多的内存。
因此,尽量的让 App 在系统内,占用足够小的内存资源,就能够下降被杀的几率,从而下次启动的时候走热启动的方式,提高用户的体验。
换一个角度来讲,让 App 占用较小的内存,也能够优化系统的速度,毕竟系统清理进程释放内存的过程,也是须要占用 CPU 资源的。在大环境下,也是有意义的。
因此,在 onTrimMemory()
的时机,对当前 App 的内存进行释放优化,就尤其重要了。
在 onTrimMemory()
回调中,应该在一些状态下清理掉不重要的内存资源。在不考虑内存泄露的状况下,有一些资源是咱们主动缓存起来,以便咱们在使用的过程当中能够快速获取,而这部分资源就是咱们清理的重点。
对于这些缓存,只要是读进内存内的都算,例如最多见的图片缓存、文件缓存等。拿图片缓存来讲,市场上,常规的图片加载库,通常而言都是三级缓存,因此在内存吃紧的时候,咱们就应该优先清理掉这部分图片缓存,毕竟图片是吃内存大户,并且再次回来的时候,虽然内存中的资源被回收掉了,咱们依然能够从磁盘或者网络上恢复它。
除了资源缓存以外,还有一些页面相关的资源,也是占据内存的,能够考虑清理掉 Activity Task 中,多余的 Activity,只保留 Root Activity 。
其实核心思想,就是根据 onTrimMemory()
回调的一些信息,来释放咱们持有的可被恢复,不那么重要的内存资源,以提升系统性能,已经保证当前 App 的进程不那么容易被系统回收。