当系统资源不足时,系统将会启动回收机制。根据进程重要性和优先级依次进行回收,直至新建进程或运行的更重要进程有足够的资源。
根据进程重要性可分为五类(解释来源于网络):
前台进程可简单理解为用户当前操作所必需的进程。
举个例子:如果当进程包含如下任一条件,即可视为前台进程:
- 用户正在交互的Activity,即Activity已调用onResume() 方法。
- 已绑定到用户正在交互的Activity的Service。
- 正在“前台”运行的 Service,即服务已调用startForeground()。
- 正在执行一个生命周期回调的 Service,如onCreate()、onStart() 或 onDestroy()。
- 正在执行其 onReceive() 方法的 BroadcastReceiver。
通常情况下,前台进程数量不是很多,系统只有在内存不足以支撑其运行的情况下才会终止它们。
没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。
举个例子:如果当进程包含如下任一条件,即可视为可见进程:
-
已绑定到可见Activity的Service。
-
用户可见的Activity,即Activity已调用其 onPause() 方法。如:
-
前台Activity启动一个透明背景的Activity。
-
前台 Activity 启动了一个对话框,允许在其后显示上一 Activity,则有可能会发生这种情况。
-
可见进程重要性弱次于前台进程,所以除非为了维持所有前台进程同时运行而必须终止,否则系统不会终止这些进程。
- 正在运行已使用 startService() 方法启动的服务且不属于上述两个更高类别进程的进程。
尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作。例如,在后台播放音乐或从网络下载数据。
- 包含目前对用户不可见的Activity的进程,即Activity已调用onStop() 方法。
这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。 通常会有很多后台进程在运行,因此它们会保存在 LRU (最近最少使用)列表中,以确保包含用户最近查看的 Activity 的进程最后一个被终止。如果某个 Activity 正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户导航回该 Activity 时,Activity 会恢复其所有可见状态。
- 不含任何活动应用组件的进程。
保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。 为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。
一、降低进程被杀死概率。
二、提升杀死后进程拉活机制。
Android 5.0以上版本,采用双进程保活基本上没用了。
JobScheduler是Android 5.0提出的定时事件方案,本例中是在循环定时任务中启动保活服务。但JobScheduler在Android 8.0+中体现不是很好,甚至定时任务会失效。
即监听亮屏和暗屏广播,实现Activity开启和关闭。
即运行应用在低电量情况下进行后台运行。
/**
* 针对N以上的Doze模式
*/
@SuppressLint("BatteryLife")
fun isIgnoreBatteryOption(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ZKeepAlive.isKeepalive) {
try {
val intent = Intent()
val packageName = context.packageName
val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
// intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
intent.data = Uri.parse("package:$packageName")
context.startActivity(intent)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
// 根据不同厂商进入自启动设置
private fun getSettingIntent(): Intent {
var componentName: ComponentName? = null
val brand = Build.BRAND
when (brand.toLowerCase(Locale.ROOT)) {
"samsung" -> componentName = ComponentName(
"com.samsung.android.sm",
"com.samsung.android.sm.app.dashboard.SmartManagerDashBoardActivity"
)
"huawei" -> componentName = ComponentName(
"com.huawei.systemmanager",
"com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity"
)
"xiaomi" -> componentName = ComponentName(
"com.miui.securitycenter",
"com.miui.permcenter.autostart.AutoStartManagementActivity"
)
"vivo" -> componentName = ComponentName(
"com.iqoo.secure",
"com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity"
)
"oppo" -> componentName = ComponentName(
"com.coloros.oppoguardelf",
"com.coloros.powermanager.fuelgaue.PowerUsageModelActivity"
)
"360" -> componentName = ComponentName(
"com.yulong.android.coolsafe",
"com.yulong.android.coolsafe.ui.activity.autorun.AutoRunListActivity"
)
"meizu" -> componentName = ComponentName(
"com.meizu.safe",
"com.meizu.safe.permission.SmartBGActivity"
)
"oneplus" -> componentName = ComponentName(
"com.oneplus.security",
"com.oneplus.security.chainlaunch.view.ChainLaunchAppListActivity"
)
}
val intent = Intent()
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
if (componentName != null) {
intent.component = componentName
} else {
intent.action = Settings.ACTION_SETTINGS
}
return intent
}
Workmanager为Android 8.0+提供了完美的定时任务方案,利用Workmanager实现一个循环任务,并在任务中启动保活服务。
如果使用应用者是合作方,不妨试试这种方案,基本上可以达到100%保活,前提条件是用户要将小组件移动桌面。
本例中是自定义倒计时小组件,并在小组件onUpdate中启动保活服务。
提高Service的优先级,在进程存在的情况下,降低系统回收几率。
-
A:android:priority="1000"最高权限。
-
B:onStartCommand返回值设置:
getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.ECLAIR ? START_STICKY_COMPATIBILITY : START_STICKY
-
C:前置服务,startForeground(int id, Notification notification)。
-
D:onDestroy()方法中重启服务。
<!--开机广播-->
<action android:name="android.intent.action.BOOT_COMPLETED" />
<!--网络状态更新-->
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
<action android:name="android.net.wifi.STATE_CHANGE" />
<action
android:name="android.net.conn.CONNECTIVITY_CHANGE"
tools:ignore="BatteryLife" />
<!--电池电量变化-->
<action android:name="android.intent.action.BATTERY_CHANGED" />
<!--应用安装状态变化-->
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<!--屏幕亮度变化-->
<action android:name="android.intent.action.SCREEN_OFF" />
<action android:name="android.intent.action.SCREEN_ON" />
<!--锁屏-->
<action android:name="android.intent.action.USER_PRESENT" />
监听系统广播,在广播中启动相关进程和保活服务。