Android应用在后台运行时如何保持屏幕常亮?
解决方案
问题根因
- 你当前用普通后台服务持有WakeLock的方案,在Android 8.0及以上系统中完全不可行:系统会在应用退到后台数分钟后主动限制后台服务的运行优先级,你持有的WakeLock会被系统强制回收,自然无法阻止屏幕熄灭。
- 你选用的
PowerManager.FULL_WAKE_LOCK已被Android官方废弃,本身兼容性就存在问题。 - 另外你最开始用
FLAG_KEEP_SCREEN_ON的时候写错了API:应该调用addFlags而不是clearFlags,不过该参数本身确实只对前台可见的Activity生效,不能满足后台需求。
修正步骤
1. 先添加必要权限
在AndroidManifest.xml中新增如下权限声明:
<!-- 唤醒锁权限 --> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- 安卓9及以上前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- 安卓13及以上需要通知权限,用于显示前台服务通知 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
2. 将普通服务修改为前台服务
前台服务的优先级远高于普通后台服务,不会被系统随意回收,WakeLock可以正常生效。修改后的ScreenOnService代码如下:
package com.example; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Service; import android.content.Intent; import android.os.Build; import android.os.IBinder; import android.os.PowerManager; import android.content.Context; public class ScreenOnService extends Service { private static final int NOTIFICATION_ID = 1; private static final String CHANNEL_ID = "screen_on_service_channel"; private PowerManager.WakeLock wakeLock; @Override public void onCreate() { super.onCreate(); // 1. 先启动前台服务 createNotificationChannel(); Notification notification = new Notification.Builder(this, CHANNEL_ID) .setContentTitle("屏幕保持常亮中") .setContentText("应用正在后台运行,保持屏幕不熄灭") .setSmallIcon(R.drawable.ic_launcher_foreground) // 替换为你自己应用的图标 .build(); startForeground(NOTIFICATION_ID, notification); // 2. 正确持有唤醒锁 PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); // 替换已废弃的FULL_WAKE_LOCK,使用SCREEN_BRIGHT_WAKE_LOCK+ACQUIRE_CAUSES_WAKEUP组合 wakeLock = powerManager.newWakeLock( PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "MyApp:KeepScreenOnTag" // 标签格式要求为 包名:自定义名称 ); // 持有唤醒锁,参数填Long.MAX_VALUE表示永久持有直到主动释放 wakeLock.acquire(Long.MAX_VALUE); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; // 服务被系统杀死后自动重启,如果你不需要可以保留原来的START_NOT_STICKY } @Override public void onDestroy() { // 释放唤醒锁 if (wakeLock != null && wakeLock.isHeld()) { wakeLock.release(); } // 停止前台服务 stopForeground(true); super.onDestroy(); } @Override public IBinder onBind(Intent intent) { return null; } // 创建通知渠道,安卓8.0及以上要求 private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( CHANNEL_ID, "屏幕常亮服务", NotificationManager.IMPORTANCE_LOW ); channel.setDescription("用于保持屏幕常亮的前台服务通知"); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } } }
3. 修改启动服务的逻辑
Android 8.0及以上启动前台服务需要调用startForegroundService,修改MainActivity的启动代码:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(getApplicationContext(), ScreenOnService.class); // 安卓8.0及以上用startForegroundService启动前台服务 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(intent); } else { startService(intent); } // 如果你需要当前Activity也保持常亮,可以加上这句 // getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); }
额外注意事项
- 安卓13及以上系统,你需要在应用启动时主动申请
POST_NOTIFICATIONS权限,否则前台服务通知无法正常显示,会导致服务启动失败。 - 小米、华为、vivo、OPPO等国产定制系统,需要手动给应用开启「自启动」「后台活动权限」「电池优化白名单」,否则系统还是会强制杀死前台服务。
内容的提问来源于stack exchange,提问作者nick_j_white
相关产品推荐
相关产品推荐

