Android内存优化之OnTrimMemory简介
一、前言
在Android开发中,内存管理是一个至关重要的课题。特别是在系统内存紧张时,如何有效地释放资源以避免应用被系统杀死,是每个开发者需要考虑的问题。其中,OnTrimMemory 回调是 Android 4.0 之后提供的一个API,这个 API 是提供给开发者的,它的主要作用是提示开发者在系统内存不足的时候,通过处理部分资源来释放内存,从而避免被 Android 系统杀死。
二、 API 介绍
2.1、哪些组件可以实现OnTrimMemory回调
Application.onTrimMemory()
Activity.onTrimMemory()
Fragement.OnTrimMemory()
Service.onTrimMemory()
ContentProvider.OnTrimMemory()
2.2、level参数的含义
可根据应用的当前所处的状态氛围以下三种情况:
2.2.1、应用正在运行时:
TRIM_MEMORY_RUNNING_MODERATE 设备开始内存不足。应用正在运行且不可杀。
TRIM_MEMORY_RUNNING_LOW 设备内存严重不足。应用正在运行且不可杀,但请释放未使用的资源以提高系统性能(这直接影响您的应用性能)。
TRIM_MEMORY_RUNNING_CRITICAL 设备内存极度不足。应用尚未被视为可杀进程,但如果应用不释放资源,系统将开始杀后台进程,因此现在应释放非关键资源以防止性能下降。
2.2.2、应用的可见性发生变化时:
TRIM_MEMORY_UI_HIDDEN 应用的用户界面不再可见,所以这是释放仅由用户界面使用的大型资源的好时机。
2.2.3、应用的进程位于后台 LRU 列表中时:
TRIM_MEMORY_BACKGROUND 系统内存不足,进程接近 LRU 列表的开头。虽然应用进程被杀的风险不高,但系统可能已经在杀 LRU 列表中的进程,因此应释放易于恢复的资源,以便进程留在列表中,并在用户返回应用时快速恢复。
TRIM_MEMORY_MODERATE 系统内存不足,应用进程接近 LRU 列表的中间。如果系统内存进一步受限,进程有可能被杀死。
TRIM_MEMORY_COMPLETE 系统内存不足,如果系统现在不恢复内存,该应用进程将是首批被杀死的进程之一。
3、示例代码
以下是官方提供的示例代码
import android.content.ComponentCallbacks2
class MainActivity : AppCompatActivity(), ComponentCallbacks2 {
/**
* 当用户界面隐藏或系统资源变低时释放内存。
* @param level 所引发的与内存相关的事件
*/
override fun onTrimMemory(level: Int) {
// 确定引发了哪个生命周期或系统事件。
when (level) {
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN -> {
// 释放当前占用内存的任何 UI 对象。用户界面移至后台。
}
ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE,
ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW,
ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL -> {
/*
释放您的应用程序运行时不需要的任何内存。应用程序运行时设备内存不足。
引发的事件表明与内存相关事件的严重程度。
如果事件是 TRIM_MEMORY_RUNNING_CRITICAL,则系统开始停止后台进程。
*/
}
ComponentCallbacks2.TRIM_MEMORY_BACKGROUND,
ComponentCallbacks2.TRIM_MEMORY_MODERATE,
ComponentCallbacks2.TRIM_MEMORY_COMPLETE -> {
/*
尽可能多地释放进程的内存。该应用在 LRU 列表中,并且系统内存不足。
引发的事件表明该应用在 LRU 列表中的位置。
如果事件是 TRIM_MEMORY_COMPLETE,则该进程是首先被终止的进程之一。
*/
}
else -> {
/*
释放任何非关键的数据结构。 该应用从系统接收到一个无法识别的内存级别值。
将此视为通用的低内存消息。
*/
}
}
}
}
三、拓展阅读
3.1、有哪些典型的使用场景
3.1.1、常驻内存的应用
一些常驻内存的应用,比如Launcher、安全中心、电话等,在用户使用过要退出的时候,需要调用OnTrimMemory来及时释放用户使用的时候所产生的多余的内存资源:比如动态生成的View、图片缓存、Fragment等。
3.1.2、有后台Service运行的应用
这些应用不是常驻内存的,意味着可以被任务管理器杀掉,但是在某些场景下用户不会去杀。这类应用包括:音乐、下载等。用户退出UI界面后,音乐还在继续播放,下载程序还在运行。这时候音乐应该释放部分UI资源和Cache.
3.2、为什么要调用OnTrimMemory
尽管系统在内存不足的时候杀进程的顺序是按照LRU Cache中从低到高来的,但是它同时也会考虑杀掉那些占用内存较高的应用来让系统更快地获得更多的内存。所以如果你的应用占用内存较小,就可以增加不被杀掉的几率,从而快速地恢复(如果不被杀掉,启动的时候就是热启动,否则就是冷启动,其速度差在2~3倍)。所以说在几个不同的OnTrimMemory回调中释放自己的UI资源,可以有效地提高用户体验。
3.3、OnTrimMemory的TRIM_MEMORY_UI_HIDDEN回调和onStop的关系
1、直接按Home键回到桌面onTrimMemory的TRIM_MEMORY_UI_HIDDEN 回调是在是onStop方法之前调用的
2、应用间切换onTrimMemory的TRIM_MEMORY_UI_HIDDEN 回调是在是onStop方法之后调用的
以上结论结论经过demo验证,大家有兴趣也可以写个demo试试看。
onTrimMemory()的TRIM_MEMORY_UI_HIDDEN回调只有当我们程序中的所有UI组件全部不可见的时候才会触发,这和onStop()方法还是有很大区别的,因为onStop()方法只是当一个Activity完全不可见的时候就会调用,比如说用户打开了我们程序中的另一个Activity。
因此,我们可以在onStop()方法中去释放一些Activity相关的资源,比如说取消网络连接或者注销广播接收器等,但是像UI相关的资源应该一直要等到onTrimMemory(TRIM_MEMORY_UI_HIDDEN)这个回调之后才去释放,这样可以保证如果用户只是从我们程序的一个Activity回到了另外一个Activity,界面相关的资源都不需要重新加载,从而提升响应速度。
3.4、OnTrimMemory和OnLowMemory的关系
在引入OnTrimMemory之前都是使用OnLowMemory回调,需要知道的是,OnLowMemory大概和 OnTrimMemory中的TRIM_MEMORY_COMPLETE级别相同,如果你想兼容api<14的机器,那么可以用 OnLowMemory来实现,否则你可以忽略OnLowMemory,直接使用OnTrimMemory即可。 现在国内api<14以下的设备基本不存在了, 大家基本可以忽略。
四、附录
Android官方文档-管理应用内存
ComponentCallbacks2官方API
从OnTrimMemory角度谈Android代码内存优化