Android 12屏幕录制保存至存储异常:服务启动即停止求助
问题排查与修复方案
1. 先搞定存储权限和路径问题
- 权限检查:
- Android 9及更早版本:必须动态申请
WRITE_EXTERNAL_STORAGE权限,确保代码中包含权限申请逻辑且用户已授权。 - Android 10+:虽然DCIM目录无需WRITE权限,但要保证目录能正常创建。在
getValues()中添加日志确认创建结果:if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) && !saveDir.isDirectory()) { boolean dirCreated = saveDir.mkdirs(); Log.d("StorageDebug", "目录创建结果: " + dirCreated + ", 路径: " + saveLocation); } - 打印
SAVEPATH完整值,确认路径无特殊字符、父目录真实存在。
- Android 9及更早版本:必须动态申请
2. 抓准MediaRecorder的异常原因
mMediaRecorder.stop()抛出RuntimeException是触发Service立即停止的核心原因,在catch块中打印完整异常栈,定位具体问题:
catch (RuntimeException e) { Log.e("RecorderCrash", "MediaRecorder停止失败: ", e); // 打印完整异常信息 if (new File(SAVEPATH).delete()) Toast.makeText(this, "ذخیره ویدیو با مشکل روبرو شد", Toast.LENGTH_SHORT).show(); }
常见触发场景:
- 未调用
mMediaRecorder.start()就执行stop:检查录制启动逻辑,确保start成功后才会进入停止流程。 - 音频源配置错误:
audioRecSource = "1"对应麦克风,若暂时不需要音频,可先关闭音频录制测试是否恢复正常。 - 分辨率/比特率超出设备支持范围:降低比特率或改用设备原生分辨率。
3. 修复重复停止Service的问题
indexFile()的扫描回调和destroyMediaProjection的finally块都调用了stopSelf(),重复停止会导致异常。删除扫描回调中的stopSelf(),仅保留finally块中的一次调用:
MediaScannerConnection.scanFile(this, toBeScannedStr, null, (path, uri) -> { Message message = mHandler.obtainMessage(); Log.e("ServiceErrors","RecorderService Index : " + message.toString()); message.sendToTarget(); // 移除此处的stopSelf() });
4. 检查MediaProjection的回调逻辑
确认mMediaProjectionCallback是否在录制启动前就触发了onStop(),导致提前执行停止逻辑。添加状态判断:
private MediaProjection.Callback mMediaProjectionCallback = new MediaProjection.Callback() { @Override public void onStop() { Log.d("ProjectionDebug", "MediaProjection被停止"); // 仅在录制状态下执行停止逻辑 if (isRecording) { destroyMediaProjection(); } } };
5. 确保Service以前台模式启动
Android 8.0+要求后台Service必须以前台模式启动,否则会被系统立即杀死。启动Service时使用startForegroundService(),并在onStartCommand中尽快显示前台通知:
@Override public int onStartCommand(Intent intent, int flags, int startId) { // 构建前台通知(需先创建通知渠道) NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "RECORDER_CHANNEL") .setSmallIcon(R.drawable.ic_recorder) .setContentTitle("正在录屏") .setContentText("录屏中...") .setPriority(NotificationCompat.PRIORITY_LOW); startForeground(1, builder.build()); // 执行录制初始化与启动逻辑 startRecording(); return START_STICKY; }
内容的提问来源于stack exchange,提问作者Dr.KeyOk
相关产品推荐
相关产品推荐

