安卓开发 录音 时间久了 进程自动挂了 录音没有录制成功怎么办呀

安卓开发 录音 时间久了 进程自动挂了 录音没有录制成功怎么办呀
https://cloud.tencent.com/developer/article/1726665

  应该是安卓系统“省电”搞的事儿,您在代码中让其加入kill白名单,让录音程序可以一直在后台运行。
  您还可以以时间或者文件大小为阈值,分段保存您的录音文件。不至少一点都没保存即使被kill,也只是丢失最后一个片段录音。


  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/7486692
  • 以下回答由chatgpt基于相关博客总结生成:

    由于没有提供具体的录音库和开发平台信息,无法提供精确的解决方案。但是可以从以下几个方面入手解决录音进程崩溃问题:

    1. 检查录音所需权限是否正确获取,并在录音过程中对录音权限进行动态申请。
    2. 在录音过程中进行音频数据的压缩处理,以减少内存消耗。
    3. 对录音进程进行后台处理,以避免前台进程挂掉导致录音无法完成。
    4. 对录音的缓存和保存进行优化,避免大量数据存储占用过多内存而导致进程崩溃。
    5. 检查录音库是否有相关的bug,尝试更新录音库或使用其他可靠的录音库。

    针对以上几点,可以从以下几个步骤来解决录音进程崩溃问题:

    步骤一:检查录音权限是否正确获取,并动态申请权限

    在AndroidManifest.xml文件中添加录音权限:

    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    

    在录音开始之前,可以动态申请录音权限:

    private void checkPermissionAndRecord() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
                != PackageManager.PERMISSION_GRANTED) {
            // Permission is not granted
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.RECORD_AUDIO},
                    MY_PERMISSIONS_REQUEST_RECORD_AUDIO);
        } else {
            startRecording();
        }
    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode,
            String[] permissions, int[] grantResults) {
        if (requestCode == MY_PERMISSIONS_REQUEST_RECORD_AUDIO) {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                startRecording();
            } else {
                // Permission denied
                Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
            }
        }
    }
    

    步骤二:对录音数据进行压缩处理

    可以使用Android自带的MediaCodec进行音频编解码,将原始录音数据进行压缩处理,以减少内存消耗。具体可以参考以下代码:

    // 初始化音频编码器
    private void initAudioCodec() {
        MediaFormat format = MediaFormat.createAudioFormat(MIME_TYPE, SAMPLE_RATE, CHANNEL_COUNT);
        format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
        format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
        try {
            mAudioEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
            mAudioEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            mAudioEncoder.start();
    
            mAudioInputBuffers = mAudioEncoder.getInputBuffers();
            mAudioOutputBuffers = mAudioEncoder.getOutputBuffers();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    // 开始录音并进行压缩处理
    private void startRecording() {
        // 初始化音频编码器
        initAudioCodec();
    
        // 初始化AudioRecord
        int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT);
        mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, bufferSize);
        mAudioRecord.startRecording();
    
        ByteBuffer[] inputBuffers = mAudioEncoder.getInputBuffers();
        ByteBuffer[] outputBuffers = mAudioEncoder.getOutputBuffers();
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        boolean isEOS = false;
        long startMs = System.currentTimeMillis();
    
        while (!Thread.interrupted()) {
            if (!isEOS) {
                int inputBufferIndex = mAudioEncoder.dequeueInputBuffer(TIMEOUT_US);
                if (inputBufferIndex >= 0) {
                    ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
                    int sampleSize = mAudioRecord.read(inputBuffer, BUFFER_SIZE);
    
                    if (sampleSize < 0) {
                        Log.e(TAG, "audio data read error: " + sampleSize);
                        break;
                    }
    
                    if (sampleSize == 0) {
                        Log.d(TAG, "audio input EOS");
                        mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                        isEOS = true;
                    } else {
                        mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, sampleSize, System.nanoTime() / 1000, 0);
                    }
                } else {
                    Log.e(TAG, "no available input buffer right now");
                }
            }
    
            int outputBufferIndex = mAudioEncoder.dequeueOutputBuffer(bufferInfo, TIMEOUT_US);
            if (outputBufferIndex >= 0) {
                ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
                ByteBuffer buffer = ByteBuffer.allocate(bufferInfo.size);
                buffer.put(outputBuffer);
                mDataList.add(buffer.array());
                Log.d(TAG, "audio output: " + buffer.capacity());
    
                mAudioEncoder.releaseOutputBuffer(outputBufferIndex, false);
            } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                // Subsequent data will conform to new format.
                Log.i(TAG, "output format changed, new format: " + mAudioEncoder.getOutputFormat());
            } else {
                Log.e(TAG, "no available output buffer right now");
            }
    
            if ((System.currentTimeMillis() - startMs) >= TIMEOUT_MS) {
                break;
            }
        }
    
        stopRecording();
    }
    

    步骤三:对录音进程进行后台处理

    可以在录音时将录音进程放入后台,并设置合适的保活机制,以避免前台进程挂掉而导致录音无法完成。具体可以参考以下代码:

    public class RecordingService extends Service {
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            startRecording();
            return START_NOT_STICKY;
        }
    
        // 开始录音
        private void startRecording() {
            // ...
            // 开始录音,并在子线程中执行
            AsyncTask.execute(new Runnable() {
                @Override
                public void run() {
                    while (!Thread.interrupted()) {
                        // 录音处理
                    }
                }
            });
        }
    }
    

    通过将录音操作放在子线程中进行,可以减少前台进程的内存消耗和占用,从而避免前台进程挂掉导致录音失败。

    步骤四:对录音缓存和保存进行优化

    对录音缓存和保存进行优化,可以采用边录音边压缩的方式,将录音数据直接存储到本地文件或云端存储中,避免录音数据过大导致进程崩溃。具体可以参考以下代码:

    // 开始录音并缓存数据到本地文件
    private void startRecordingAndCacheToFile() {
        FileOutputStream fos = null;
        try {
            File file = new File(getExternalCacheDir(), RECORD_FILE_NAME);
            fos = new FileOutputStream(file);
    
            byte[] buffer = new byte[1024];
            int len;
    
            while ((len = mAudioRecord.read(buffer)) != -1) {
                // 将录音数据写入本地文件
                fos.write(buffer, 0, len);
                fos.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    通过将录音数据边录音边缓存到本地文件或云端存储中,可以有效减轻内存压力,避免录音数据过大导致进程崩溃。

    步骤五:检查录音库是否有相关的bug,并进行更新或替换

    可以根据录音

防止进程回收,了解一下