[Android]让APP进入后台后不被杀掉(保活)

news/2025/2/25 12:49:09/

在 Android 系统中,应用在进入后台后,系统可能会因为各种原因(如内存不足、电池优化等)对其进行强制退出。虽然无法完全保证应用永远不会被系统强制退出,但可以采取一些措施来减少这种情况的发生。以下是几种常见的方法:

1. 使用前台服务 (Foreground Service)

前台服务可以让系统知道你的应用正在执行一些重要的任务,即使在后台也不会轻易被杀掉。你可以在应用启动时创建一个前台服务。

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"package="com.mofang.call.callphone"><!-- 声明前台服务的权限 --><uses-permission android:name="android.permission.FOREGROUND_SERVICE" /><applicationandroid:name=".App"android:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:extractNativeLibs="true"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:requestLegacyExternalStorage="true"android:roundIcon="@mipmap/ic_launcher"android:supportsRtl="true"android:theme="@style/Theme.MFCallPhone"android:usesCleartextTraffic="true"tools:targetApi="31"><serviceandroid:name=".MyForegroundService"android:foregroundServiceType="location|dataSync|mediaPlayback"android:permission="android.permission.FOREGROUND_SERVICE"tools:ignore="ForegroundServicePermission" /></application>
</manifest>

MyForegroundService

import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompatclass MyForegroundService : Service() {companion object {const val CHANNEL_ID = "ForegroundServiceChannel"}override fun onCreate() {super.onCreate()createNotificationChannel()startForegroundService()}private fun createNotificationChannel() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {val serviceChannel = NotificationChannel(CHANNEL_ID,"Foreground Service Channel",NotificationManager.IMPORTANCE_DEFAULT)val manager = getSystemService(NotificationManager::class.java)manager.createNotificationChannel(serviceChannel)}}@SuppressLint("ForegroundServiceType")private fun startForegroundService() {val notificationIntent = Intent(this, StartPageActivity::class.java) // MainActivity::class.java)val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent,PendingIntent.FLAG_IMMUTABLE) // 0val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID)//.setContentTitle("前台服务")//.setContentText("前台保活服务") // 你的应用程序在前台运行.setSmallIcon(R.mipmap.icon_home_2_s).setContentIntent(pendingIntent).build()startForeground(1, notification)}override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {// 在这里处理服务启动请求// START_NOT_STICKY,表示如果服务被系统杀掉,不会自动重启。如果系统因为内存不足而杀掉了服务,它不会自动重启服务。这适用于不需要保证服务持续运行的场景。// START_STICKY,如果系统因为内存不足而杀掉了服务,它会在资源可用时自动重启服务,但不重新传递最后一个 Intent。这适用于不需要传递数据给服务的场景,例如音乐播放服务。// START_REDELIVER_INTENT,如果系统因为内存不足而杀掉了服务,它会在资源可用时自动重启服务,并重新传递最后一个 Intent 给服务。这适用于需要保证任务完成的场景,例如文件下载服务。return START_STICKY}override fun onBind(intent: Intent?): IBinder? {return null}
}

启动前台服务:

/// 保活
private fun baohuo() {// 启动前台服务val serviceIntent = Intent(this, MyForegroundService::class.java)startService(serviceIntent)// 绑定服务val serviceConnection = object : ServiceConnection {override fun onServiceConnected(name: ComponentName?, service: IBinder?) {NSLog("Service connected")}override fun onServiceDisconnected(name: ComponentName?) {NSLog("Service disconnected")}}bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE)
}   

2. 使用 WorkManager

WorkManager 是一个推荐的处理后台任务的工具,特别是需要确保任务在系统重启后或在长时间间隔后还能继续执行的任务。它可以自动处理不同版本的设备和电池优化策略。

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.PowerManager
import android.provider.Settings
import androidx.work.Constraints
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.mofang.call.callphone.utils.NSLog
import java.util.concurrent.TimeUnit/// 2. 使用 WorkManager
/// 应用被杀掉,WorkManager 仍然会继续执行已调度的任务。WorkManager 旨在提供可靠的后台执行,即使应用被杀掉或设备重启,它也会尝试重新执行任务。
var curCountt: Double = 0.0
class MyWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {override fun doWork(): Result {// 这里是你需要执行的任务curCountt += 1NSLog("MyWorker is running = $curCountt")// 调度下一个任务scheduleNextWork()// 如果任务成功完成,返回 Result.success()return Result.success()}private fun scheduleNextWork() {val workRequest = OneTimeWorkRequestBuilder<MyWorker>().setInitialDelay(1, TimeUnit.MINUTES)  // 设置延迟时间.setConstraints(Constraints.Builder().setRequiresCharging(false) // 不需要设备充电.setRequiresBatteryNotLow(false) // true电池电量不低.build()).build()WorkManager.getInstance(applicationContext).enqueue(workRequest)}}
/// 保活
private fun baohuo() {// 请求忽略电池优化requestIgnoreBatteryOptimizations(this)// WorkManagerval sharedPreferences = getSharedPreferences(KEY_PREFS_NAME, Context.MODE_PRIVATE)val workDispatched = sharedPreferences.getBoolean(KEY_WORK_DISPATCHED, false)if (!workDispatched) {NSLog("111")// 创建初始任务请求val initialWorkRequest = OneTimeWorkRequestBuilder<MyWorker>().setInitialDelay(1, TimeUnit.MINUTES)  // 设置延迟时间.setConstraints(Constraints.Builder().setRequiresCharging(false) // 不需要设备充电.setRequiresBatteryNotLow(false) // true电池电量不低.build()).build()// 调度初始任务WorkManager.getInstance(this).enqueue(initialWorkRequest)// 更新状态sharedPreferences.edit().putBoolean(KEY_WORK_DISPATCHED, true).apply()} else {//NSLog("222")}
}

3. 避免电池优化

你可以请求用户将你的应用加入电池优化白名单。用户可以手动在设置中添加,也可以通过代码请求用户取消电池优化。

import android.content.Intent
import android.os.Build
import android.provider.Settings
import android.content.Context
import android.content.pm.PackageManager/// 3. 避免电池优化
/// 请求用户将你的应用加入电池优化白名单。用户可以手动在设置中添加,也可以通过代码请求用户取消电池优化。
fun requestIgnoreBatteryOptimizations(context: Context) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {val packageName = context.packageName// 通过 Context 获取 PowerManager 实例,用于检查和请求忽略电池优化。val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager// 检查当前应用是否被忽略电池优化. 使用 PowerManager 的 isIgnoringBatteryOptimizations 方法检查当前应用是否已被忽略电池优化。如果未被忽略,则继续执行请求忽略电池优化的操作。if (!pm.isIgnoringBatteryOptimizations(packageName)) {// 创建一个 Intent,其动作为 Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,并将数据设置为当前应用的包名。然后启动这个 Intent,请求用户允许应用忽略电池优化。val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)intent.data = Uri.parse("package:$packageName")NSLog("请求用户允许应用忽略电池优化")context.startActivity(intent)}}
}
/// 保活
private fun baohuo() {// 请求忽略电池优化requestIgnoreBatteryOptimizations(this)
}        

4. 使用 JobScheduler

JobScheduler 是另一个适用于 Android 5.0 及以上版本的后台任务工具。

import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.ComponentName
import android.content.Contextfun scheduleJob(context: Context) {val componentName = ComponentName(context, MyJobService::class.java)val jobInfo = JobInfo.Builder(1, componentName).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).setPersisted(true) // 确保任务在设备重启后继续存在.build()val jobScheduler = context.getSystemService(JobScheduler::class.java)jobScheduler.schedule(jobInfo)
}

5. 使用 AlarmManager

在极端情况下,你可以使用 AlarmManager 定期触发一些操作,确保应用在后台不会被完全忽视。

import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intentfun scheduleAlarm(context: Context) {val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManagerval intent = Intent(context, MyBroadcastReceiver::class.java)val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0)alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis() + 60000, // 设定延迟时间60000, // 重复间隔pendingIntent)
}

6. 定期保存应用状态

即使采取了以上措施,系统仍可能在某些情况下杀掉你的应用。确保在应用被杀掉时能够适当地保存和恢复关键任务和状态是很重要的。

override fun onSaveInstanceState(outState: Bundle) {// 保存关键数据outState.putString("key", "value")super.onSaveInstanceState(outState)
}override fun onRestoreInstanceState(savedInstanceState: Bundle) {super.onRestoreInstanceState(savedInstanceState)// 恢复关键数据val value = savedInstanceState.getString("key")
}

注意:

通过以上方法,你可以尽量减少应用在后台被系统强制退出的可能性,但无法完全避免。确保应用在被杀掉后能够正确恢复是一个更为实际和稳妥的方案。


http://www.ppmy.cn/news/1574843.html

相关文章

005:Cesium.viewer 知识详解、示例代码

查看本专栏目录 - 本文是第 005个API内容详解 vue+cesium 示例教程200+目录 文章目录 一、Cesium.Viewer 知识详解1. 主要用途2. 构造函数与参数3. 常用属性(1)`viewer.scene`(2)`viewer.camera`(3)`viewer.entities`(4)`viewer.clock`4. 常用方法(1)`viewer.zoomTo(…

2024年第十五届蓝桥杯青少 图形化编程(Scratch)省赛中级组真题——截取递增数

截取递增数 背景信息 递增数&#xff1a;如果一个大于9的正整数各个数位上的数&#xff0c;从左到右是逐渐变大的&#xff0c;那么就称这个数为递增数。 例如124、248 是递增数。 给你一个不含0的九位数&#xff0c;请找出从这个九位数中能截取出的所有递增数。例如:115367…

Starlink卫星动力学系统仿真建模第十讲-基于SMC和四元数的卫星姿态控制示例及Python实现

基于四元数与滑模控制的卫星姿态控制 一、基本原理 1. 四元数姿态表示 四元数运动学方程&#xff1a; 3. 滑模控制设计 二、代码实现&#xff08;Python&#xff09; 1. 四元数运算工具 import numpy as npdef quat_mult(q1, q2):"""四元数乘法""…

子集II力扣--90

目录 题目 思路 代码 题目 给你一个整数数组 nums &#xff0c;其中可能包含重复元素&#xff0c;请你返回该数组所有可能的 子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。返回的解集中&#xff0c;子集可以按 任意顺序 排列。 示例 1&#xff1a; 输入…

【Python修仙编程】(二) Python3灵源初探(1)

第一部分&#xff1a;变量的修炼——灵气的凝练 林羽站在练气期的起点&#xff0c;面前是师傅玄天真人的法典。玄天真人翻开第一页&#xff0c;上面写着&#xff1a;“变量是灵气的容器&#xff0c;修仙者通过凝练灵气来修炼。” “师傅&#xff0c;变量是啥&#xff1f;”林…

ESP32学习笔记_Bluetooth(3)——GATT

文章目录 GATTConfiguration and RolesGATT Profile HierarchyServiceService DeclarationService IncludeInclude Declaration CharacteristicCharacteristic DeclarationCharacteristic Value DeclarationCharacteristic Descriptor DeclarationsCharacteristic Extended Pro…

第二章 基础算法

目录 第二章 基础算法1、时间复杂度与空间复杂度一、算法复杂度二、时间复杂度三、空间复杂度四、OJ评判结果 2、一维前缀和与一维差分一维前缀和一维差分 第二章 基础算法 1、时间复杂度与空间复杂度 一、算法复杂度 如何衡量一个算法的好坏呢&#xff1f; 是从时间效率和空…

Redis速成(1)

课程&#xff1a;黑马程序员Redis入门到实战教程&#xff0c;深度透析redis底层原理redis分布式锁企业解决方案黑马点评实战项目_哔哩哔哩_bilibili 1.Mybatis与MybatisPlus: 参考springboot&#xff0c;需要额外写mapper.class&#xff0c;在方法上Select等 在ssm中&#xff0…