为什么我会在这种状态下获得NPE

时间:2015-06-22 08:51:52

标签: android audiorecord

我正在尝试从设备录制音频。

我创建了一个AudioRecord对象,并在活动周期内对其进行管理。

当我的应用程序转到后台时,它会停止,当它在前台时会继续。

当录制正在运行时,我想将录制器中的样本转换为字节数组

这是我用来做的代码:

private void startRecorder() {
    Log.d(TAG, "before start recording");
    myBuffer = new byte[2048];
    audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
    audioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_DTMF, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
    myRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, 2048);

    myThread = new Thread() {
        public void run() {
            while (true) {
                if (myRecorder != null && myRecorder.getState() == AudioRecord.RECORDSTATE_RECORDING) {
                    myRecorder.read(myBuffer, 0, 2048);
                    recordingSampleNumber++;
                    if (recordingSampleNumber % 10 == 0) {
                        Log.d(TAG, "recording sample number:" + recordingSampleNumber);
                    }
                }
            }
        }
    };
    myThread.setPriority(Thread.MAX_PRIORITY);

    myRecorder.startRecording();
    myThread.start();
    Log.d(TAG, "after start recording");
}

我的问题是:每隔一段时间我就会收到以下错误:

06-22 11:44:21.057: E/AndroidRuntime(17776): Process: com.example.microphonetestproject2, PID: 17776
06-22 11:44:21.057: E/AndroidRuntime(17776): java.lang.NullPointerException: Attempt to invoke virtual method 'int android.media.AudioRecord.getState()' on a null object reference
06-22 11:44:21.057: E/AndroidRuntime(17776):    at com.example.microphonetestproject2.MicrophoneTestApp$3.run(MicrophoneTestApp.java:108)

我的问题是:为什么我在myRecorder.getState()上获得一个NPE,在我编写"if myRecorder!=null"之前只有半行

1 个答案:

答案 0 :(得分:1)

这看起来像是一个并发问题。

似乎在检查myRecorder!= null之后,该变量实际上在另一个线程中设置为null,这是可能的,因为您可能知道线程并行运行。

我建议您锁定对象并执行循环。然后,没有人会不合时宜地访问它,即意外。

while (true) {
    synchronized (myRecorder) {
        if (myRecorder != null && myRecorder.getState() == AudioRecord.RECORDSTATE_RECORDING) {
            myRecorder.read(myBuffer, 0, 2048);
            recordingSampleNumber++;
            if (recordingSampleNumber % 10 == 0) {
                Log.d(TAG, "recording sample number:" + recordingSampleNumber);
            }
        }
    }
}

虽然这可能会解决您的问题,但您应该以其他方式处理它,例如:而不是将变量设置为null以取消线程,使用内置的interruptjoin方法:

private Thread mRecorderThread;

private void startRecorder() {
    myRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000,
            AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, 2048);

    mRecorderThread = new Thread() {
        public void run() {
            while (true) {
                if (!isInterrupted() && myRecorder.getState() == AudioRecord
                        .RECORDSTATE_RECORDING) {
                    myRecorder.read(myBuffer, 0, 2048);
                    recordingSampleNumber++;
                    if (recordingSampleNumber % 10 == 0) {
                        Log.d(TAG, "recording sample number:" + recordingSampleNumber);
                    }
                }
            }
        }
    };
    mRecorderThread.setPriority(Thread.MAX_PRIORITY);
    myRecorder.startRecording();
    mRecorderThread.start();
    Log.d(TAG, "after start recording");
}

private void stopRecorder() {
    mRecorderThread.interrupt();
    // Wait for the thread to finish (for the interruption to take effect)
    try {
        mRecorderThread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    myRecorder.stop();
}
正如您所理解的那样,

interrupt()会中断线程,但它不会立即终止它。在join()的帮助下,您可以在中断线程后等待线程完成。