24、电量管理:Doze模式适配、后台播放限制、省电策略
做车载多媒体开发,电量管理是个绕不开的坎儿。
你想想看,车机不像手机,手机没电了可以随时充。车机要是耗电太快,用户可能连导航都撑不到目的地。更别说,现在很多新能源车的中控屏一开就是半天,后台还在播音乐、跑地图。嗯,这里面的门道,我今天跟你好好聊聊。
24.1 Doze模式适配:别让你的App在后台“睡着”
Android从6.0开始引入了Doze模式。说白了,就是系统检测到设备长时间未使用,会进入深度休眠。这时候,你的App如果还在后台偷偷跑,系统会直接“断网+冻结”。
我在项目中遇到过一个问题:用户把车停在停车场,音乐App还在后台播放。结果Doze模式一触发,网络断了,下一首歌死活加载不出来。用户回来一上车,发现播放器卡住了。
核心要点: Doze模式下,网络访问会被挂起,JobScheduler和AlarmManager的触发频率会被大幅降低。
24.1.1 如何适配Doze模式?
我个人习惯的做法是:
- 使用高优先级FCM消息:如果必须唤醒设备,用FCM的“高优先级”消息。但注意,别滥用。
- 申请临时白名单:通过
PowerManager.requestPowerWhitelist()让用户手动将你的App加入白名单。 - 使用JobScheduler替代AlarmManager:JobScheduler在Doze模式下有更好的兼容性。
// 申请临时白名单示例
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm != null && !pm.isIgnoringBatteryOptimizations(getPackageName())) {
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
注意: 不要滥用白名单申请。Google Play有审核机制,滥用会被下架。车载场景下,建议只在播放音乐或导航时申请。
24.2 后台播放限制:Android 12以后的新规
Android 12开始,系统对后台播放做了更严格的限制。以前你可以在后台随便播音乐,现在不行了。系统会检测到你的App在后台长时间播放,然后直接杀掉进程。
为什么会这样?因为有些流氓App在后台偷偷播无声音频,保持进程存活。Google看不下去了,直接一刀切。
24.2.1 如何绕过限制?
其实不是绕过,而是合规使用。我建议的做法是:
- 使用前台服务:播放音乐时,必须启动前台服务,并显示通知。这是最标准的做法。
- 通知必须包含“停止”按钮:用户可以通过通知直接停止播放。
- 不要长时间占用音频焦点:当其他App请求音频焦点时,你的App应该暂停或降低音量。
// 启动前台服务播放音乐
Intent serviceIntent = new Intent(this, MusicPlaybackService.class);
startForegroundService(serviceIntent);
// 在Service中创建通知
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("正在播放")
.setContentText("歌曲名称")
.setSmallIcon(R.drawable.ic_music)
.addAction(R.drawable.ic_stop, "停止", stopPendingIntent)
.build();
startForeground(NOTIFICATION_ID, notification);
避坑指南: 我曾经在Android 13上踩过一个坑——前台服务通知必须立即显示,否则系统会直接抛异常。所以记得在
onStartCommand()里第一时间调用startForeground()。
24.3 省电策略:从代码层面优化
省电不是让用户去设置里关功能,而是开发者从代码层面做优化。我总结了几个实战经验:
24.3.1 减少网络请求
网络请求是耗电大户。每次请求都要唤醒射频模块,功耗很高。我的做法是:
- 批量请求:把多个小请求合并成一个。
- 使用缓存:图片、歌曲列表等静态数据,优先从缓存读取。
- 降低刷新频率:比如歌词同步,不需要每秒都请求,可以每5秒同步一次。
24.3.2 优化定位服务
车载场景下,定位是必须的。但你可以:
- 使用被动定位:当其他App已经获取了位置,你的App直接读取缓存。
- 降低定位精度:导航时用高精度,后台时用低精度。
- 合理设置更新间隔:不要设置成0,至少1000ms以上。
// 合理设置定位请求
LocationRequest request = new LocationRequest.Builder(Priority.PRIORITY_BALANCED_POWER_ACCURACY, 5000)
.setMinUpdateIntervalMillis(2000)
.build();
24.3.3 屏幕与音频优化
屏幕和音频是车机上最耗电的两个硬件。我的建议:
- 降低屏幕亮度:在后台播放时,可以适当降低亮度。
- 使用低功耗音频解码:比如AAC比MP3更省电。
- 关闭不必要的传感器:比如陀螺仪、加速度计,不用时就注销监听。
24.4 知识体系总览
下面这张图,是我自己整理的电量管理知识体系。你可以对照着看,查漏补缺。
24.5 实战中的避坑指南
最后,分享几个我踩过的坑:
- 不要依赖
WAKE_LOCK:以前我习惯用WakeLock保持CPU唤醒,但Android 12以后,系统会强制释放。现在改用前台服务才是正道。 - 注意测试环境:Doze模式在模拟器上很难复现。我建议用真机,通过
adb shell dumpsys deviceidle force-idle强制进入Doze模式测试。 - 用户感知很重要:省电策略不能影响用户体验。比如降低定位精度,导航时千万别降,否则用户会骂娘。
我的习惯: 每次发布新版本前,我都会在车上实际跑一遍,开着导航、播着音乐,然后锁车走人。半小时后回来看看App还在不在运行。这个土办法,比任何测试工具都管用。
电量管理这块,说白了就是平衡。你要在功能完整性和省电之间找到那个平衡点。别为了省电阉割功能,也别为了功能把电耗光。嗯,多测试、多优化,慢慢就有感觉了。
公众号:蓝海资料掘金营,微信deep3321