ANR occurs occasionally when users play sound effects. The log uploaded by UmENG is as follows
You can see that the ANR is set when executing the mediaPlayer. prepare method
Cause analysis:
Mediaplayer has two methods for preparing resources: prepare and prepareAsync. The difference is that the two methods are synchronous and asynchronous
Let’s look at the source code for prepare and prepareAsync (C++ layer).
status_t MediaPlayer::prepare() { ALOGV("prepare"); Mutex::Autolock _l(mLock); mLockThreadId = getThreadId(); if (mPrepareSync) { mLockThreadId = 0; return -EALREADY; } mPrepareSync = true; status_t ret = prepareAsync_l(); if (ret ! = NO_ERROR) { mLockThreadId = 0; return ret; } if (mPrepareSync) { mSignal.wait(mLock); // wait for prepare done mPrepareSync = false; } ALOGV("prepare complete - status=%d", mPrepareStatus); mLockThreadId = 0; return mPrepareStatus; } status_t MediaPlayer::prepareAsync() { ALOGV("prepareAsync"); Mutex::Autolock _l(mLock); return prepareAsync_l(); }Copy the code
PrepareAsync_l (); prepareAsync (); prepareAsync_l()
if (mPrepareSync) {
mSignal.wait(mLock); // wait for prepare done
mPrepareSync = false;
}
Copy the code
The wait method is called to make the player wait for the resource to be prepared, so that the Java layer realizes the effect of synchronous call. The notify method is called to wake up the player thread after preparing
void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
...
case MEDIA_PREPARED:
ALOGV("prepared");
mCurrentState = MEDIA_PLAYER_PREPARED;
if (mPrepareSync) {
ALOGV("signal application thread");
mPrepareSync = false;
mPrepareStatus = NO_ERROR;
mSignal.signal();
}
break;
}
Copy the code
By reading the source code, can be determined because the prepare method is similar in the current thread to read the resource directly, even if the resource file is a network resources, when the network condition is bad or weak network circumstances, so the chance of ANR will be very high, and if the request is interrupted or file is not complete, can also lead to failure, One solution is to play a voice in the following way
MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource(url); mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mp.start(); }});Copy the code