Android锁屏时MediaRecorder无法录音,已申请WakeLock仍无效如何解决
解决方案
1. 补全前台服务的必要配置
Android 8.0及以上版本要求前台服务必须在启动后5秒内调用startForeground()展示通知,同时需要在清单文件中声明对应权限和服务属性,否则熄屏后系统会降低进程优先级,收回麦克风访问权限。
清单文件配置
在AndroidManifest.xml中添加如下声明:
<!-- 基础权限 --> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- 前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- Android 12+ 前台麦克风权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" /> <!-- 服务配置 --> <service android:name=".BackgroundService" android:exported="false" android:foregroundServiceType="microphone" />
前台服务初始化
在Service的onCreate方法最开头添加前台服务启动逻辑,不要等到定时器触发再执行:
@Override public void onCreate() { super.onCreate(); // 第一步:启动前台服务 String channelId = "record_service_channel"; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( channelId, "录音服务", NotificationManager.IMPORTANCE_LOW ); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } Notification notification = new NotificationCompat.Builder(this, channelId) .setContentTitle("正在录音") .setContentText("录音服务运行中") .setSmallIcon(R.mipmap.ic_launcher) .build(); startForeground(1001, notification); // 第二步:提前申请WakeLock,不要等定时器触发再申请 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "FlexRat::Tag"); wakeLock.setReferenceCounted(false); wakeLock.acquire(); // 原有定时器逻辑 final long RECORDING_INTERVAL = 30000; TimerTask recordingTask = new TimerTask() { public void run() { Log.i("Debug", "Recording Task"); stopRecording(); startRecording(); } }; Timer recordingTimer = new Timer(); recordingTimer.scheduleAtFixedRate(recordingTask, 0, RECORDING_INTERVAL); }
2. 优化MediaRecorder的调用逻辑
你当前每次切分文件都会销毁重建MediaRecorder,熄屏状态下频繁申请麦克风资源很容易被系统拦截,导致setAudioSource失败。
推荐优化方案(无需重建实例)
Android 10及以上可以直接用系统自带的切分逻辑,不需要每次重建MediaRecorder:
private MediaRecorder recorder; private void startRecording() { Log.i("Info", "NEW RECORDING"); try { if (recorder == null) { recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); // 直接设置30秒自动切分 recorder.setMaxDuration(30000); recorder.setOnInfoListener((mr, what, extra) -> { if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) { // 切分文件,重新设置输出路径 recorder.stop(); recorder.reset(); // 复用原有配置 recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); recorder.setOutputFile(getNewFilePath()); recorder.prepare(); recorder.start(); } }); } recorder.setOutputFile(getNewFilePath()); recorder.prepare(); recorder.start(); } catch (Exception e) { e.printStackTrace(); } } private String getNewFilePath() { Date today = Calendar.getInstance().getTime(); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.ENGLISH); String reportDate = formatter.format(today); File instanceRecordDirectory = new File(getStoragePath()); if (!instanceRecordDirectory.exists()) { instanceRecordDirectory.mkdirs(); } return instanceRecordDirectory.getAbsolutePath() + File.separator + reportDate + ".mp4"; }
3. 适配定制ROM权限限制
小米、华为、OPPO等国产定制系统有额外的后台限制规则,需要引导用户手动开启以下权限:
- 录音权限设置为「始终允许」,不要选「使用时允许」
- 开启「允许后台活动」「后台弹出界面」权限
- 关闭应用的电池优化,加入耗电保护白名单
4. Android 14+适配
Android 14新增了后台麦克风权限自动回收机制,应用退到后台超过30秒没有用户交互就会收回麦克风权限,需要在申请录音权限时明确引导用户开启「始终允许录音」的权限。
内容的提问来源于stack exchange,提问作者Anwar El Bo
相关产品推荐
相关产品推荐

