2016-04-25 101 views
2

我正在尝试构建一个简单的应用程序来记录语音命令并将其发送到亚马逊Alexa,为此,我按照此tutorial来录制语音命令。下面的代码片段使我烦恼:MediaRecorder在设置音频源时引发异常(android开发)

import android.app.Activity; 
import android.media.MediaPlayer; 
import android.media.MediaRecorder; 
import android.os.Bundle; 
import android.os.Environment; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.view.View; 
import android.widget.Button; 
import android.widget.Toast; 

import java.io.IOException; 


public class MainActivity extends Activity { 
    Button play,stop,record; 
    private MediaRecorder myAudioRecorder; 
    private String outputFile = null; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    play=(Button)findViewById(R.id.button3); 
    stop=(Button)findViewById(R.id.button2); 
    record=(Button)findViewById(R.id.button); 

    stop.setEnabled(false); 
    play.setEnabled(false); 
    outputFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/recording.3gp";; 

    myAudioRecorder=new MediaRecorder(); 
    myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); ***ERROR*** 
    myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 
    myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB); 
    myAudioRecorder.setOutputFile(outputFile); 

抛出下面的错误堆栈:

FATAL EXCEPTION: main 
                      Process: com.example.michael.test, PID: 20504 
                      java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.michael.test/com.example.michael.test.MainActivity}: java.lang.RuntimeException: setAudioSource failed. 
                       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416) 
                       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
                       at android.app.ActivityThread.-wrap11(ActivityThread.java) 
                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
                       at android.os.Handler.dispatchMessage(Handler.java:102) 
                       at android.os.Looper.loop(Looper.java:148) 
                       at android.app.ActivityThread.main(ActivityThread.java:5417) 
                       at java.lang.reflect.Method.invoke(Native Method) 
                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
                      Caused by: java.lang.RuntimeException: setAudioSource failed. 
                       at android.media.MediaRecorder.setAudioSource(Native Method) 
                       at com.example.michael.test.MainActivity.onCreate(MainActivity.java:37) 
                       at android.app.Activity.performCreate(Activity.java:6251) 
                       at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107) 
                       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369) 
                       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)  
                       at android.app.ActivityThread.-wrap11(ActivityThread.java)  
                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)  
                       at android.os.Handler.dispatchMessage(Handler.java:102)  
                       at android.os.Looper.loop(Looper.java:148)  
                       at android.app.ActivityThread.main(ActivityThread.java:5417)  
                       at java.lang.reflect.Method.invoke(Native Method)  
                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)  
                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)  
04-25 12:35:39.109 20504-20504/com.example.michael.test I/Process: Sending signal. PID: 20504 SIG: 9 

所有google搜索指向的问题是没有正确设定为应用访问音频源的权利,但是我不AndroidManifest.xml中包括以下几行:

<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" /> 

所以我很茫然还有什么可以错在这里去...我与Android开发梭哈io使用LG Nexus 5与Android 6.0.1进行测试。 SDK设置为Android 5.0。

回答

13

经过大约三天的研究,我决定在MyRecorderApp运行时检查应用程序管理器(设置>应用程序>应用程序管理器> MyRecorderApp>权限)。事实证明,MyRecorderApp没有“危险的权限”(就像谷歌称之为),所以我先手动打开它们(我的应用程序从此停止崩溃),这导致我找到以下信息(来自Google和this blog) 。

从Android 6.0(API级别23)开始,用户在应用程序运行时为应用程序授予权限,而不是在安装应用程序时授予应用程序权限。从谷歌

报价:Complete explanation from Google's developers website

下面是代码的短版,我从谷歌的网页和上述来源。这个想法是要求用户在第一次启动应用程序时,即在安装之后,允许他们录制音频并访问手机的文件夹。它的工作对我的Android M(6.0.1),安卓2.1.1工作室

添加以下声明

private boolean permissionToRecordAccepted = false; 
private boolean permissionToWriteAccepted = false; 
private String [] permissions = {"android.permission.RECORD_AUDIO", "android.permission.WRITE_EXTERNAL_STORAGE"}; 

添加以下重写代码块。您也可以通过按“Alt”+“Insert”(Windows)或“control”+“O”(Mac)将其添加到Android Studio模板中,然后查找列表中的onRequestPermissionsResult选项。

@Override 
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 
    super.onRequestPermissionsResult(requestCode, permissions, grantResults); 
    switch (requestCode){ 
     case 200: 
      permissionToRecordAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED; 
      permissionToWriteAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED; 
      break; 
    } 
    if (!permissionToRecordAccepted) MainActivity.super.finish(); 
    if (!permissionToWriteAccepted) MainActivity.super.finish(); 

} 

最后,将这个“if”语句添加到您的onCreate。

@Override 
protected void onCreate(Bundle savedInstanceState) { 

    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    // Add the following code to your onCreate 
    int requestCode = 200; 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
     requestPermissions(permissions, requestCode); 
    } 

} 
+0

完美答案。解决了我的一个大问题。如果可能的话,会多加几分钟。 – filipebarretto