Android 进程回收原理
分配与回收应用内存
Android 是一个多任务的系统,为了维护多任务环境的正常运行,系统会为每个应用分配内存上限。如果 App 在达到容量上限后尝试分配更多的内存,则可能会造成 OOM 。
在用户切换应用时,Android 会将非前台应用保留在缓存中。非前台应用就是指用户看不到或未运行前台服务(如音乐播放)的应用。例如,当用户首次启动某个应用时,系统会为其创建一个进程;但当用户离开此应用时,该进程不会退出。系统会将该进程保留在内存中,以便稍后用户返回时,重复使用该进程,提高应用的切换速度。
如果此时进程仍在内存中的后台应用占用了大量的目前不需要的内存资源,那么即使用户未在前台使用这个 App,它也会影响系统的整体性能。当系统资源(如内存)不足时,它将会终止缓存中的进程。系统还会考虑终止占用最多内存的进程以释放 RAM。
进程与应用生命周期
当内存不足,而其他更急于为用户提供服务的进程又需要内存时,Android 可能会决定在某一时刻关闭某个进程。正因如此,系统会销毁在被终止进程中运行的应用组件。当这些组件需再次运行时,系统将为其重启进程。
决定终止哪个进程时,Android 系统会权衡其对用户的相对重要性。例如,相较于拥有当前可见的 Activity 的进程而言,系统更有可能关闭不再可见的后台进程。因此,是否终止某个进程的决定取决于该进程中所运行组件的状态。
应用进程的生命周期并不由应用本身直接控制,而是由系统综合多种因素来确定的,比如系统所知道的正在运行的应用部分、这些内容对用户的重要程度,以及系统中可用的总内存量。这是 Android 非常独特的一个基本功能。
为了确定在内存不足时应该终止哪些进程,Android 会根据每个进程中运行的组件以及这些组件的状态,将它们放入“重要性层次结构”。这些进程类型包括(按重要性排序):
- 前台进程,是用户目前执行操作所需的进程。在不同的情况下,进程可能会因为其所包含的各种应用组件而被视为前台进程。
- 可见进程,正在进行用户当前知晓的任务,因此终止该进程会对用户体验造成明显的负面影响。
- 服务流程,包含一个已使用
startService()方法启动的 Service。虽然用户无法直接看到这些进程,但它们通常正在执行用户关心的任务(例如后台网络数据上传或下载),因此系统会始终使此类进程保持运行,除非没有足够的内存来保留所有前台和可见进程。 - 缓存进程,是目前不需要的进程,因此,如果其他地方需要内存,系统可以根据需要自由地终止该进程。
自定义无障碍服务属于一个单独的应用程序进程中,所以自定义的无障碍服务并没有特殊权限,和普通的应用程序进程一样,会在内存不足时被回收。
无障碍服务的生命周期完全由系统管理,并遵循既定的服务生命周期。启动无障碍服务仅由用户在设备设置中明确打开服务触发。
尽管无障碍服务的生命周期完全由系统管理,但是用户自定义的无障碍服务本质上还是一个 Service 。
自定义无障碍服务保活实现
通过将自定义的无障碍服务设置为前台服务,可以有效的避免被系统杀死(用户自己手动杀死无法解决)。
class AccessibilityDemoService: BaseAccessibilityService() {
override fun onCreate() {
super.onCreate()
val notification = createForegroundNotification()
startForeground(1, notification)
}
override fun onDestroy() {
stopForeground(true)
super.onDestroy()
}
//创建前台通知,可写成方法体,也可单独写成一个类
private fun createForegroundNotification(): Notification {
//前台通知的id名,任意
val channelId = "ForegroundService"
//前台通知的名称,任意
val channelName = "Service"
//发送通知的等级,此处为高,根据业务情况而定
val importance = NotificationManager.IMPORTANCE_HIGH;
//判断Android版本,不同的Android版本请求不一样,以下代码为官方写法
val channel = NotificationChannel(channelId, channelName, importance)
channel.lightColor = Color.BLUE
channel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
notificationManager?.createNotificationChannel(channel)
//最终创建的通知,以下代码为官方写法
//注释部分是可扩展的参数,根据自己的功能需求添加
return NotificationCompat.Builder(this,channelId)
.setContentTitle("填写通知的标题")
.setContentText("填写通知的内容")
.setTicker("通知的提示语")
.build()
}
}
其他建议
建议引导用户将自定义无障碍服务设置为系统服务,或开启自启动,这样能够避免被杀死的问题。