android 息屏后被挂起停止运行解决
android app有很多应用场景需要在后台开启服务, 比如后台实时上传位置数据, 不停发送心跳包等等, 但是在息屏休眠后, app往往没有按照我们设想的运行. 我网上查了很多资料才总结出了一套可以运行在后台方案
- 设置前台服务
- 获取电源锁
- 设置service清理后自动重启
- 提高app优先级
- 设置电池优化白名单
- 播放无声音乐(上面都设置了但是华为android10还是不行, 加上这个才可以了. 加上这个耗电比较凶)
1. 设置前台服务
1.1 启动服务
fun startService(context: Context) {
val intent = Intent(context, MyService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
}
1.2 在onStartCommand中将服务设置在前台
/**创建前台通知**/
private fun creatNotification() {
val channelName = "通信服务"
val builder: Notification.Builder?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (null == notificationManager) {
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
val importance = NotificationManager.IMPORTANCE_HIGH
val notificationChannel = NotificationChannel(CHANNEL_ID, channelName, importance)
notificationChannel.description = channelName
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.BLUE
notificationChannel.setShowBadge(true)
notificationChannel.enableLights(true)
notificationManager?.createNotificationChannel(notificationChannel)
builder = Notification.Builder(applicationContext, CHANNEL_ID)
} else {
builder = Notification.Builder(applicationContext)
}
builder.setSmallIcon(AppUtils.getAppIconId()) //设置通知图标
.setContentTitle(channelName) //设置通知标题
.setContentText("正在后台运行") //设置通知内容
.setAutoCancel(false) //用户触摸时,自动关闭
.setOngoing(true) //设置处于运行状态
.setWhen(System.currentTimeMillis())
mNotification = builder.build()
mNotification?.flags = Notification.FLAG_ONGOING_EVENT
mNotification?.flags = Notification.FLAG_NO_CLEAR
mNotification?.flags = Notification.FLAG_FOREGROUND_SERVICE
}
//将服务设置在前台
startForeground(1, mNotification)
1.3 在onDestroy中退出前台服务
stopForeground(true)
2 获取电源锁
2.1 使用电源锁的注意事项
电源锁必须成对使用, 手机息屏那么你先获取的电源锁也会被释放, 所以我们必须监听手机的亮屏息屏广播来控制电源锁的使用
2.2 注册屏幕亮屏息屏广播
/** 注册息屏亮屏监听 start**/
private fun registReceiver() {
val mIntentFilter = IntentFilter()
mIntentFilter.addAction(Intent.ACTION_SCREEN_ON)
mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF)
registerReceiver(mScreenStatusReceiver, mIntentFilter)
}
private fun unregistReceiver() {
unregisterReceiver(mScreenStatusReceiver)
}
private var mScreenStatusReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
Intent.ACTION_SCREEN_ON -> {
LogUtils.dTag(TAG, "亮屏")
stopAcquire()
}
Intent.ACTION_SCREEN_OFF -> {
LogUtils.dTag(TAG, "息屏")
acquire()
}
else -> {}
}
}
}
2.3 电源锁获取和释放
/* 保持屏幕熄灭后 cpu 还一直运行 */
private var wl: PowerManager.WakeLock? = null
@SuppressLint("InvalidWakeLockTag")
private fun acquire() {
try {
val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
if (wl == null)
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, SipManagerService::class.java.name)
wl?.acquire(10 * 60 * 60 * 1000L /*10 minutes*/)
} catch (e: Exception) {
e.printStackTrace()
}
}
//清除唤醒
private fun stopAcquire() {
try {
if (wl?.isHeld == true)
wl?.release()
wl = null
} catch (e: Exception) {
e.printStackTrace()
}
}
3 设置service清理后自动重启
在onStartCommand中返回START_STICKY
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
4 提高app优先级
在application中提高app优先级, 申请大内存, 防止内存不足时候被清理
// android:largeHeap="true" , android:priority="1000"
<application
android:name=".app.App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:persistent="true"
android:priority="1000"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
5 设置电池优化白名单
/**
* 忽略电池优化
*/
@RequiresApi(Build.VERSION_CODES.M)
fun ignoreBatteryOptimization(activity: Activity) {
val powerManager = getSystemService(POWER_SERVICE) as PowerManager
val hasIgnored = powerManager.isIgnoringBatteryOptimizations(activity.packageName)
// 判断当前APP是否有加入电池优化的白名单,如果没有,弹出加入电池优化的白名单的设置对话框。
if (hasIgnored.not()) {
val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
intent.data = Uri.parse("package:" + activity.packageName)
startActivity(intent)
}
}
6 播放无声音乐
6.1 在onCreate中播放无声音乐
private var mMediaPlayer: MediaPlayer? = null
// 开始播放无声音乐
private fun startMediaPlayer() {
mMediaPlayer = MediaPlayer.create(this.applicationContext, R.raw.silent_music)
mMediaPlayer?.isLooping = true
if (mMediaPlayer?.isPlaying?.not() == true) {
mMediaPlayer?.start()
}
}
6.2 在onDestroy中停止播放音乐
private fun stopMediaPlayer() {
mMediaPlayer?.stop()
mMediaPlayer?.release()
mMediaPlayer = null
}
代码片段+无声音乐下载地址: 传送门