Java.lang.RuntimeException: 启动失败

8

我正在尝试使用MediaRecorder在我的一个Activity中录制音频。部分代码如下。

File file = new File(AppConstants.MSGS_DIR, filename);
MediaRecorder recorder = new MediaRecorder();
recorder.setAudioSource(AudioSource.MIC);
recorder.setOutputFormat(OutputFormat.THREE_GPP);
recorder.setAudioEncoder(AudioEncoder.AMR_WB);
recorder.setOutputFile(file.getAbsolutePath());
try {
    recorder.prepare();
    recorder.start();
} catch (IOException e) {
    System.out.println("Exception: " + e.getMessage());
}

我在清单文件中授予了以下权限。
(Note: 保留了HTML标签)
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />

但是在 recorder.start() 这一行代码处,我遇到了运行时异常。Logcat 显示以下错误信息。

09-23 15:47:54.462: E/AndroidRuntime(8697): FATAL EXCEPTION: main
09-23 15:47:54.462: E/AndroidRuntime(8697): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mypackage/com.mypackage.RecordingActivity}: java.lang.RuntimeException: start failed.
09-23 15:47:54.462: E/AndroidRuntime(8697):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2250)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2300)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at android.app.ActivityThread.access$600(ActivityThread.java:144)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1295)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at android.os.Handler.dispatchMessage(Handler.java:99)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at android.os.Looper.loop(Looper.java:150)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at android.app.ActivityThread.main(ActivityThread.java:5162)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at java.lang.reflect.Method.invokeNative(Native Method)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at java.lang.reflect.Method.invoke(Method.java:525)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:744)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at dalvik.system.NativeStart.main(Native Method)
09-23 15:47:54.462: E/AndroidRuntime(8697): Caused by: java.lang.RuntimeException: start failed.
09-23 15:47:54.462: E/AndroidRuntime(8697):     at android.media.MediaRecorder.start(Native Method)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at com.mypackage.RecordingActivity.startRecording(RecordingActivity.java:169)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at com.mypackage.RecordingActivity.onCreate(RecordingActivity.java:107)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at android.app.Activity.performCreate(Activity.java:5288)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
09-23 15:47:54.462: E/AndroidRuntime(8697):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2214)

我尝试在stackoverflow上寻找与错误对应的问题,但无法从中得出有效的答案。请检查一下这个代码,告诉我哪里错了。

顺便说一下,这段代码只在特定的设备上失败了。我是否遗漏了额外的权限?


@MysticMagic,我正在寻找音频录制,我觉得它与宽度和高度无关。你指出的答案是针对视频录制的 :) - Jeeri
1
这段代码只在特定设备上失败了 - 你可能需要包含更多关于这些设备的细节。比如,它们的平台版本是什么?AudioEncoder.AMR_WB仅从API10开始提供。 - ozbek
@shoerat:设备上代码无法运行:<i>索尼爱立信4.0.3版本,华硕Genfone 4.3版本</i>。代码在Moto-g 4.4.4,Note 2的OS版本4.4.2上可以正常工作。 - Jeeri
1
@shoerat AppConstants.MSGS_DIR = Environment.getExternalStorageDirectory().getPath() + "/MYAppFolder/"; 而文件名是一些随机字符串。我成功创建了该文件夹和文件(文件名为fileName0),但无法向其中写入任何数据。 - Jeeri
但无法向其写入任何数据。所以,很可能这就是异常的原因?也许可以尝试使用不同的路径(例如 Context.getExternalFilesDir())? - ozbek
显示剩余3条评论
2个回答

6

由于一些设备不支持3GP格式和AudioEncoder.AMR_WB编码,因此它们无法被支持。请点击这里查看支持的格式。

请使用以下代码,这将支持最大数量的设备。

recorder.setOutputFormat(OutputFormat.MPEG_4);
recorder.setAudioEncoder(AudioEncoder.AAC);

安卓2.2怎么样? - محمد
1
安卓的M版本怎么样了? - user5399980
2
将其设置为默认值是否适用于每个设备?例如:recorder.setOutputFormat(OutputFormat.DEFAULT); recorder.setAudioEncoder(AudioEncoder.DEFAULT); - SimpleCoder

0
如果您正在使用Api 23,则需要先授予权限,然后再开始录制。
     private boolean checkAndRequestPermissions() {
            int permissionSendMessage = ContextCompat.checkSelfPermission(this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE);
            int locationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
            List<String> listPermissionsNeeded = new ArrayList<>();
            if (locationPermission != PackageManager.PERMISSION_GRANTED) {
                listPermissionsNeeded.add(Manifest.permission.RECORD_AUDIO);
            }
            if (permissionSendMessage != PackageManager.PERMISSION_GRANTED) {
                listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
            }
            if (!listPermissionsNeeded.isEmpty()) {
                ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),REQUEST_ID_MULTIPLE_PERMISSIONS);
                return false;
            }
            return true;
        }
      @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        Log.d("TAG", "Permission callback called-------");
        switch (requestCode) {
            case REQUEST_ID_MULTIPLE_PERMISSIONS: {

                Map<String, Integer> perms = new HashMap<>();
                // Initialize the map with both permissions
                perms.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.RECORD_AUDIO, PackageManager.PERMISSION_GRANTED);
                // Fill with actual results from user
                if (grantResults.length > 0) {
                    for (int i = 0; i < permissions.length; i++)
                        perms.put(permissions[i], grantResults[i]);
                    // Check for both permissions
                    if (perms.get(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
                            && perms.get(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
                        Log.d("TAG", "sms & location services permission granted");
                        // process the normal flow

                        pager = (ViewPager) findViewById(R.id.pager);
                        pager.setAdapter(new MyAdapter(getSupportFragmentManager()));
                        tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
                        tabs.setViewPager(pager);
                        //else any one or both the permissions are not granted
                    } else {
                        Log.d("TAG", "Some permissions are not granted ask again ");
                        //permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
//                        // shouldShowRequestPermissionRationale will return true
                        //show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
                        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ||
                                ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
                            showDialogOK("SMS and Location Services Permission required for this app",
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            switch (which) {
                                                case DialogInterface.BUTTON_POSITIVE:
                                                    checkAndRequestPermissions();
                                                    break;
                                                case DialogInterface.BUTTON_NEGATIVE:
                                                    // proceed with logic by disabling the related features or quit the app.
                                                    break;
                                            }
                                        }
                                    });
                        }
                        //permission is denied (and never ask again is  checked)
                        //shouldShowRequestPermissionRationale will return false
                        else {
                            Toast.makeText(this, "Go to settings and enable permissions", Toast.LENGTH_LONG)
                                    .show();
                            //                            //proceed with logic by disabling the related features or quit the app.
                        }
                    }
                }
            }
        }

    }

    private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", okListener)
                .create()
                .show();
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接