In my app, I have a ListView of music items and when I click an item, I fetch its corresponding mp3 URL to stream in my MediaPlayer. I set the MediaPlayer's datasource and more everytime the user clicks on the Play button. Now the problem is when I click Play button, and scroll the ListView the screen freezes then a dialog opens:
AppName is not responding.
Would you like to close it?
Wait OK
but I couldn't get the stacktrace but it said something like:
ANR my.package.name.AppName ...
Reason: keyDispatchingTimedOut
I've read to place my process inside a background thread to not make the UI thread wait. This is my current implementation but the problem still persists:
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();
What I did was place a runOnUiThread inside Thread (not working), I tried Thread only (not working), and also tried Asynctask inside its doInBackground but the player is playing at the background and cannot be stopped but I haven't tried placing it inside onPostExecute
I have a feeling I'm missing something. One thing's for sure, I should really place it inside a background thread but which one? Any idea is accepted, thank you!
EDIT: So, I changed my implementation but it still persists:
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();
by the way, I based it on the android website here.
Ok, your code executes in main thread. It's not good idea initialize a player. Totally you didn't change anything from first code to second.
ANR appears in string player.prepare(). Try to use playerAsync instead of. It will be prepare player asynchronous or you remove this:
and make all job in background thread.
And read about AsyncTask - this is a good class to do some work in the background. Much more useful than using ordinary threads.
The right way looks like it: