在Android应用程序中,为了保证应用的正常运行和稳定性,有时需要对进程进行保活。以下是一些实现进程保活的方法:
-
使用前台服务:将服务调用startForeground()方法,并传入一个通知对象,将该服务置于前台运行状态。这样可以使得该服务的优先级更高,从而减少被系统杀死的概率。
-
使用JobScheduler:使用这个API可以让应用程序以更低的功耗周期性地执行任务,从而避免长时间占用CPU资源。
-
使用AlarmManager:使用这个API可以让应用程序在指定的时间间隔内执行任务。例如,可以设置一个闹钟,每隔一段时间唤醒应用程序并执行一些操作。
-
使用守护进程:启动一个后台守护进程,监控应用程序的状态并在应用程序被杀死时重新启动它。需要注意的是,在Android 5.0(API级别21)及以上版本中,使用守护进程需要申请额外的权限。
-
使用双进程保活:启动两个相互绑定的进程,在其中一个进程被杀死时,另一个进程可以重新启动它。需要注意的是,在Android 10(API级别29)及以上版本中,双进程保活可能会造成安全漏洞,因此已被禁用。
-
使用WorkManger:这个谷歌最新推出的持久性任务执行api,用于取代JobScheduler,这是目前比较可靠的保活机制,涉及内容太多就不在这赘述,具体可参考WorkManger
需要注意的是,为了避免滥用和浪费系统资源,Android系统不断升级后,已经严格限制应用程序使用过多的后台资源和保活机制。因此,在实现进程保活时,应该考虑到性能和电池寿命等因素,并仔细评估其对用户体验和系统稳定性的影响。
下面介绍3种进程保活的示例:
前台服务
当使用前台服务(Foreground Service)来实现进程保活时,需要创建一个Service,并在onCreate()方法中调用startForeground()方法。以下是一个示例代码:
使用前台服务先声明权限:
<!-- 使用前台服务的权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
class MyService : Service() {
private val NOTIFICATION_ID = 1
private val CHANNEL_ID = "foreground_service_channel"
override fun onCreate() {
super.onCreate()
//创建通知渠道
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_LOW
)
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
//创建通知
val notificationBuilder =
NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Foreground Service")
.setContentText("Service is running...")
.setPriority(NotificationCompat.PRIORITY_LOW)
//启动前台服务
startForeground(NOTIFICATION_ID, notificationBuilder.build())
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}
当Service处于前台运行状态时,即使应用程序在后台运行时,系统也会认为该服务是重要的,并尽可能避免将其杀死。
需要注意的是,使用前台服务来实现进程保活可以一定程度上提高进程存活率,但同时也会占用更多的系统资源(例如CPU和内存)
JobScheduler
当使用JobScheduler API来实现进程保活时,需要继承JobService并重写onStartJob()方法。以下是一个示例代码:
首先,在AndroidManifest.xml文件中声明JobService:
<service android:name=".MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
然后,创建一个类并继承JobService,并实现onStartJob()和onStopJob()方法:
class MyJobService : JobService() {
private val TAG = "MyJobService"
override fun onStartJob(params: JobParameters?): Boolean {
Log.d(TAG, "onStartJob")
//执行任务,处理耗时操作
return false
}
override fun onStopJob(params: JobParameters?): Boolean {
Log.d(TAG, "onStopJob")
return false
}
}
在onStartJob()方法中,可以执行一些需要保活的耗时操作。当任务完成后,返回false表示该任务已经执行完毕。
接下来,在应用程序中创建一个JobScheduler对象,并调用schedule()方法来定期执行任务:
val jobId = 1
val jobInfo = JobInfo.Builder(jobId, ComponentName(this, MyJobService::class.java))
.setPeriodic(15 * 60 * 1000) //每隔15分钟执行一次任务
.setPersisted(true)
.build()
val jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
jobScheduler.schedule(jobInfo)
上述代码中,setPeriodic()方法指定了任务的周期性执行间隔,单位为毫秒。在这个示例中,每隔15分钟执行一次任务。setPersisted(true)方法则表示当设备重启后,该任务仍然需要继续执行。
需要注意的是,JobScheduler API仅适用于Android 5.0(API级别21)及以上的系统版本
守护进程
当使用守护进程来实现进程保活时,需要创建一个后台服务(用于监控应用程序状态)和一个守护进程(用于在应用程序被杀死时重新启动它)。以下是一个示例代码:
<!-- 使用前台服务的权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
- 后台服务
class MyService : Service() {
private val TAG = "MyService"
private val INTERVAL = 5 * 1000L //轮询间隔时间:5秒
override fun onCreate() {
Log.d(TAG, "onCreate")
super.onCreate()
startForeground(1, Notification())
startMonitor()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
private fun startMonitor() {
Thread {
while (true) {
val isAppRunning = isAppRunning(this)
if (!isAppRunning) {
Log.d(TAG, "App is killed, restarting...")
startApp(this)
}
try {
Thread.sleep(INTERVAL)
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
}.start()
}
/**
* 判断当前应用程序是否在运行中
*/
private fun isAppRunning(context: Context): Boolean {
val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val processInfos = am.runningAppProcesses
if (processInfos != null) {
for (info in processInfos) {
if (info.processName == packageName) {
return true
}
}
}
return false
}
/**
* 启动应用程序
*/
private fun startApp(context: Context) {
val intent = context.packageManager.getLaunchIntentForPackage(packageName)
if (intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
}
}
}
上述代码中,MyService是一个后台服务,它会周期性地检测应用程序的状态(使用isAppRunning()方法判断当前应用程序是否在运行中),如果应用程序被杀死了,则会重新启动它(使用startApp()方法启动应用程序)。
2.守护进程
class MyDaemonProcess : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("MyDaemonProcess", "onStartCommand")
val serviceName = MyService::class.java.name
val packageName = applicationContext.packageName
if (!isServiceRunning(packageName, serviceName)) {
Log.d("MyDaemonProcess", "Starting service...")
startService(Intent(applicationContext, MyService::class.java))
}
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
/**
* 判断指定的服务是否正在运行
*/
private fun isServiceRunning(packageName: String, serviceName: String): Boolean {
val am = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val runningServices = am.getRunningServices(Integer.MAX_VALUE)
if (runningServices != null && !runningServices.isEmpty()) {
for (serviceInfo in runningServices) {
val name = serviceInfo.service.className
if (serviceName == name) {
return true
}
}
}
return false
}
}
上述代码中,MyDaemonProcess是一个守护进程,它会在应用程序被杀死时自动启动,并检测后台服务(MyService)是否正在运行,如果没有运行,则会重新启动它。
以上就是关于进程保活的一些思路,实际过程中,安卓APP使用环境千变万化,各种厂商系统优化限制,以上保活机制都不是完全可靠的,唯一的真正能实现保活的就是做到像微信那样加入厂商白名单,不过其他企业想做到这样基本是不太可能的,除非自制ROM。
本文探讨了Android中实现进程保活的几种方法,包括前台服务、JobScheduler、AlarmManager、守护进程和双进程保活。尽管Android系统限制了后台资源的使用,但通过合理利用这些机制,可以提高应用的稳定性和持久运行。文章提供了代码示例,阐述了每种方法的工作原理和注意事项,强调在实际应用中需要考虑系统资源和用户体验。
5248

被折叠的 条评论
为什么被折叠?



