ANR Причина ключ DispatchingTimedOut MediaPlayer
В моем приложении у меня есть ListView музыкальных элементов, и когда я щелкаю элемент, я выбираю соответствующий URL-адрес mp3 для потоковой передачи в MediaPlayer. Я устанавливаю источник данных MediaPlayer и многое другое каждый раз, когда пользователь нажимает кнопку Play. Теперь проблема в том, что когда я нажимаю кнопку Play и прокручиваю ListView, экран останавливается, и открывается диалоговое окно:
AppName is not responding.
Would you like to close it?
Wait OK
но я не мог получить трассировку стека, но он сказал что-то вроде:
ANR my.package.name.AppName ...
Reason: keyDispatchingTimedOut
Я прочитал, чтобы поместить мой процесс в фоновый поток, чтобы не заставлять поток пользовательского интерфейса ждать. Это моя текущая реализация, но проблема все еще сохраняется:
Thread t = new Thread() {
public void run() {
SampleActivity.this.runOnUiThread(new Runnable() {
public void run() {
try {
mp.reset();
mp.setDataSource(musicURI);
mp.prepare();
mp.start();
songSeekBar.setEnabled(true);
// Changing Button Image to stop image
btnPlay.setImageResource(R.drawable.btn_stop);
// set Progress bar values
songSeekBar.setProgress(0);
songSeekBar.setMax(100);
// Updating progress bar
updateProgressBar();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
songSeekBar.setEnabled(false);
songTotalDurationLabel.setText("0:00");
songCurrentDurationLabel.setText("0:00");
Log.d(Constant.TAG_SAMPLE, musicTitle
+ " mp3 file not found.");
e.printStackTrace();
}
}
});
}
};
t.start();
Что я сделал, это место runOnUiThread
внутри Thread
(не работает), я пытался Thread
только (не работает), а также пытался Asynctask
внутри его doInBackground
но игрок играет на заднем плане и не может быть остановлен, но я не пытался поместить его внутрь onPostExecute
У меня такое чувство, что я что-то упускаю. Одно можно сказать наверняка, я действительно должен поместить его в фоновый поток, но какой именно? Любая идея принята, спасибо!
РЕДАКТИРОВАТЬ: Итак, я изменил свою реализацию, но она все еще сохраняется:
Thread thread = new Thread() {
public void run() {
Handler refresh = new Handler(Looper.getMainLooper());
refresh.post(new Runnable() {
public void run() {
// Play song
try {
mp.reset();
mp.setDataSource(globalSongIndex);
mp.prepare();
mp.start();
songSeekBar.setEnabled(true);
// Changing Button Image to pause image
btnPlay.setImageResource(R.drawable.btn_stop);
// set Progress bar values
songSeekBar.setProgress(0);
songSeekBar.setMax(100);
// Updating progress bar
updateProgressBar();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
songSeekBar.setEnabled(false);
songTotalDurationLabel.setText("0:00");
songCurrentDurationLabel.setText("0:00");
Log.d(Constant.TAG_MYPAGE, musicTitle + " mp3 file not found.");
e.printStackTrace();
}
}
});
}
};
thread.start();
кстати, я основал его на сайте Android здесь.
2 ответа
Хорошо, ваш код выполняется в основном потоке. Это не очень хорошая идея инициализировать игрока. В целом вы ничего не меняли с первого кода на второй.
ANR появляется в строке player.prepare(). Попробуйте использовать playerAsync вместо. Будет подготовлен игрок асинхронно или вы удалите это:
Handler refresh = new Handler(Looper.getMainLooper());
refresh.post(new Runnable() {
public void run() {
и сделать всю работу в фоновом потоке.
И прочитайте об AsyncTask - это хороший класс для работы в фоновом режиме. Гораздо полезнее, чем обычные темы.
Правильный путь выглядит так:
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(YourURI);
mp.setOnPreparedListener(new OnPreparedListener() {
public void onPrepared(MediaPlayer mp)
{
long duration = mp.getDuration();
mp.start();
}
});
mp.prepareAsync();
Я не могу дать вам мою реализацию, извините, приятель принадлежит моей компании, я могу сказать, что в вашем потоке удалите этот SampleActivity.this.runOnUiThread(new Runnable() { . В тот момент, когда вы вызываете mp.start, создайте другой поток с таким ocode
Thread.sleep(1000);
SampleActivity.this.runOnUiThread(new Runnable() {
public void run() {
// Update UI
try {
// Updating progress bar
updateProgressBar();
}};
Это будет воспроизводить ваш файл в одном потоке, а затем иметь другой поток, который спит в течение 1 секунды, а затем вызывает метод в основном потоке для обновления пользовательского интерфейса.