Android实现进程保活的思路

本文探讨了Android中实现进程保活的几种方法,包括前台服务、JobScheduler、AlarmManager、守护进程和双进程保活。尽管Android系统限制了后台资源的使用,但通过合理利用这些机制,可以提高应用的稳定性和持久运行。文章提供了代码示例,阐述了每种方法的工作原理和注意事项,强调在实际应用中需要考虑系统资源和用户体验。

在Android应用程序中,为了保证应用的正常运行和稳定性,有时需要对进程进行保活。以下是一些实现进程保活的方法:

  1. 使用前台服务:将服务调用startForeground()方法,并传入一个通知对象,将该服务置于前台运行状态。这样可以使得该服务的优先级更高,从而减少被系统杀死的概率。

  2. 使用JobScheduler:使用这个API可以让应用程序以更低的功耗周期性地执行任务,从而避免长时间占用CPU资源。

  3. 使用AlarmManager:使用这个API可以让应用程序在指定的时间间隔内执行任务。例如,可以设置一个闹钟,每隔一段时间唤醒应用程序并执行一些操作。

  4. 使用守护进程:启动一个后台守护进程,监控应用程序的状态并在应用程序被杀死时重新启动它。需要注意的是,在Android 5.0(API级别21)及以上版本中,使用守护进程需要申请额外的权限。

  5. 使用双进程保活:启动两个相互绑定的进程,在其中一个进程被杀死时,另一个进程可以重新启动它。需要注意的是,在Android 10(API级别29)及以上版本中,双进程保活可能会造成安全漏洞,因此已被禁用。

  6. 使用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"/>
  1. 后台服务
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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猫King

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值