Я изучаю разработку для Android и использую класс MediaRecorder для записи звука. И logcat говорит, что приложение падает в методе stop() и выдает IllegalStateException. Я не понимаю, почему он падает, и я вызываю метод stop перед запуском.
public class MainActivity extends AppCompatActivity {
private MediaRecorder grabacion;
private String archivoSalida = null;
private Button btn_recorder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_recorder = (Button)findViewById(R.id.btn_rec);
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO,}, 1000);
}
}
public void Recorder(View view){
if (grabacion == null){
archivoSalida = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Grabacion.mp3";
grabacion = new MediaRecorder();
grabacion.setAudioSource(MediaRecorder.AudioSource.MIC);
grabacion.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
grabacion.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
grabacion.setOutputFile(archivoSalida);
try{
grabacion.prepare();
grabacion.start();
} catch (IOException e){
}
btn_recorder.setBackgroundResource(R.drawable.rec);
Toast.makeText(getApplicationContext(), "Grabando...", Toast.LENGTH_SHORT).show();
} else if (grabacion != null){
grabacion.stop();
grabacion.release();
grabacion = null;
btn_recorder.setBackgroundResource(R.drawable.stop_rec);
Toast.makeText(getApplicationContext(), "Grabación finalizada", Toast.LENGTH_SHORT).show();
}
}
public void reproducir(View view) {
MediaPlayer mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(archivoSalida);
mediaPlayer.prepare();
} catch (IOException e){
}
mediaPlayer.start();
Toast.makeText(getApplicationContext(), "Reproduciendo audio", Toast.LENGTH_SHORT).show();
}}
Это файл манифеста:
<?xml version = "1.0" encoding = "utf-8"?>
<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name = "android.permission.RECORD_AUDIO"/>
<application
android:allowBackup = "true"
android:icon = "@mipmap/ic_launcher"
android:label = "@string/app_name"
android:roundIcon = "@mipmap/ic_launcher_round"
android:supportsRtl = "true"
android:theme = "@style/AppTheme">
<activity android:name = ".MainActivity">
<intent-filter>
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
And what logcat says:
E/MediaRecorder: stop called in an invalid state: 4
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.recorder, PID: 5386
java.lang.IllegalStateException: Could not execute method for android:onClick
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:414)
at android.view.View.performClick(View.java:7870)
at android.widget.TextView.performClick(TextView.java:14970)
at android.view.View.performClickInternal(View.java:7839)
at android.view.View.access$3600(View.java:886)
at android.view.View$PerformClick.run(View.java:29363)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:7948)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:409)
at android.view.View.performClick(View.java:7870)
at android.widget.TextView.performClick(TextView.java:14970)
at android.view.View.performClickInternal(View.java:7839)
at android.view.View.access$3600(View.java:886)
at android.view.View$PerformClick.run(View.java:29363)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:7948)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
Caused by: java.lang.IllegalStateException
at android.media.MediaRecorder._stop(Native Method)
at android.media.MediaRecorder.stop(MediaRecorder.java:1440)
at com.example.recorder.MainActivity.Recorder(MainActivity.java:55)
at java.lang.reflect.Method.invoke(Native Method)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:409)
at android.view.View.performClick(View.java:7870)
at android.widget.TextView.performClick(TextView.java:14970)
at android.view.View.performClickInternal(View.java:7839)
at android.view.View.access$3600(View.java:886)
at android.view.View$PerformClick.run(View.java:29363)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:7948)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
I/Process: Sending signal. PID: 5386 SIG: 9
Спасибо!
В документации для метода stop()
указано, что он выдаст IllegalStateException
если он вызывается перед start()
Поскольку это, кажется, единственный раз, когда эта ошибка будет выброшена, это, скорее всего, то, что происходит и в вашем случае.
Взгляните на свой Recorder()
метод. Единственный раз, когда stop()
будет вызываться, это когда ваша переменная не равна нулю. Это означает, что ваш экземпляр был правильно инициализирован.
Однако, поскольку возникает исключение, это означает, что даже если ваша переменная ссылается на экземпляр MediaRecorder
, он не был запущен.
Чтобы узнать почему, взгляните на код, который должен запускать ваш MediaRecorder
:
try {
grabacion.prepare();
grabacion.start();
} catch (IOException e){
}
Хотя он находится внутри конструкции try-catch, блок catch на самом деле не содержит никакого кода, поэтому любые ошибки просто игнорируются.
Следовательно, проблема, с которой вы столкнулись, является результатом того, что grabacion.prepare();
или grabacion.start();
не удается, что приводит к тому, что рекордер не запускается.
Учитывая, что start()
выдает только IllegalStateException
согласно документации ,
вызов prepare()
должен быть причиной проблемы. Это также соответствует моему собственному опыту, так как при звонке prepare()
многое может пойти не так. Вот что он делает на основе его описания в документации:
Подготавливает рекордер к началу захвата и кодирования данных. Этот метод должен вызываться после настройки желаемых аудио- и видеоисточников, кодировщиков, формата файла и т. д., но до start().
Так что, как вы понимаете, мне сейчас нелегко определить точную причину. Однако я могу добавить, что вы использовали Environment.getExternalStorageDirectory()
, который устарел с API 29 для улучшения конфиденциальности пользователей. Хотя это может быть проблемой в вашем случае, я не могу подтвердить это с полной уверенностью.
Чтобы точно узнать, что вызывает ошибку, вы должны использовать этот IOException
, который вы получаете в этом try-catch. Вы можете, например, зарегистрировать его трассировку стека, чтобы узнать больше о проблеме.
Здорово, что в итоге получилось. Я рад, что смог помочь :).
Вы были правы, я попробовал приложение на устройстве с Android 8 вместо 10, и оно отлично работает, поэтому я изменил метод .getExternalStorageDirectory() на другой, и теперь он работает на Android 8 и 10, спасибо. для вашей помощи