调用MediaPlayer.reset()时出现IllegalStateException

24

Android MediaPlayer的文档显示,在调用reset()时没有无效状态:http://developer.android.com/reference/android/media/MediaPlayer.html#Valid_and_Invalid_States(无效状态被列为{},或者说是“none”)。

然而,我在调用 reset() 时看到了一个IllegalStateException异常:

java.lang.IllegalStateException
at android.media.MediaPlayer._reset(Native Method)
at android.media.MediaPlayer.reset(MediaPlayer.java:1061)
at com.example.android.player.AsyncPlayer$AsyncHandler.handleMessage(AsyncPlayer.java:654)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.os.HandlerThread.run(HandlerThread.java:60)

文档是不正确的吗?


嗯,看起来我把“MediaPlayer”和另一个主题混淆了。对于造成的困惑,我很抱歉。 :) - Wroclai
4个回答

30

没有看到你的代码很难确定问题,但我认为你可能在调用release()后又调用了reset()方法?

根据文档:

当使用new创建一个MediaPlayer对象或者调用reset()之后,该对象处于空闲状态。当调用release()方法之后,对象则进入结束状态。介于这两种状态之间的是MediaPlayer对象的生命周期。

你可能是在有效的生命周期之外调用了reset方法。


13
调用 release() 后再调用 reset() 会抛出 IllegalStateException 异常。 - Jakob Eriksson

9
我遇到了你的问题,Skyler。
你是正确的。文档没有显示mediaPlayer.reset()无效状态,但这不是文档中第一个不准确的地方。
我注意到的是,有效状态列表没有列出“任何”状态;它列出了除两个状态之外的每个具体状态:准备和结束。
我进行了实验,但在尝试调用release()时,我无法让IllegalStateExceptionMediaPlayer有希望处于PREPARING状态(使用prepareAsync())时被抛出。我不能保证它不会发生,但我无法让它发生。在那种情况下,我看到以下日志消息:
04-11 11:41:54.740: E/MediaPlayer(4930): error (1, -2147483648)
04-11 11:41:54.748: E/MediaPlayer(4930): Error (1,-2147483648)

是的,两个错误消息都会出现,一个是小写的 "error",另一个是大写的 "Error",但没有抛出异常。

然而,在调用 release() 后调用 reset(),然后就会出现错误:

04-11 11:45:05.232: E/AndroidRuntime(5046): FATAL EXCEPTION: main
04-11 11:45:05.232: E/AndroidRuntime(5046): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.helloandroid/com.android.helloandroid.HelloAndroidActivity}: java.lang.RuntimeException: java.lang.IllegalStateException
04-11 11:45:05.232: E/AndroidRuntime(5046):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1696)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1716)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at android.app.ActivityThread.access$1500(ActivityThread.java:124)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:968)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at android.os.Handler.dispatchMessage(Handler.java:99)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at android.os.Looper.loop(Looper.java:123)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at android.app.ActivityThread.main(ActivityThread.java:3806)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at java.lang.reflect.Method.invokeNative(Native Method)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at java.lang.reflect.Method.invoke(Method.java:507)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at dalvik.system.NativeStart.main(Native Method)
04-11 11:45:05.232: E/AndroidRuntime(5046): Caused by: java.lang.RuntimeException: java.lang.IllegalStateException
04-11 11:45:05.232: E/AndroidRuntime(5046):     at com.android.helloandroid.HelloAndroidActivity.crashMediaPlayer(HelloAndroidActivity.java:423)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at com.android.helloandroid.HelloAndroidActivity.onCreate(HelloAndroidActivity.java:87)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1660)
04-11 11:45:05.232: E/AndroidRuntime(5046):     ... 11 more
04-11 11:45:05.232: E/AndroidRuntime(5046): Caused by: java.lang.IllegalStateException
04-11 11:45:05.232: E/AndroidRuntime(5046):     at android.media.MediaPlayer._reset(Native Method)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at android.media.MediaPlayer.reset(MediaPlayer.java:1112)
04-11 11:45:05.232: E/AndroidRuntime(5046):     at com.android.helloandroid.HelloAndroidActivity.crashMediaPlayer(HelloAndroidActivity.java:421)
04-11 11:45:05.232: E/AndroidRuntime(5046):     ... 14 more

因此,The Modern Ink 的猜测是正确的。在“END”状态下(即在调用“release()”之后),MediaPlayer.reset()会抛出IllegalStateException
在我的情况下,我发现我在onPause()中调用了release(),但在onResume()中没有做任何初始化MediaPlayer的操作。因此,在调用reset()时它处于“END”状态。
根据http://developer.android.com/reference/android/media/MediaPlayer.html

一旦MediaPlayer对象处于End状态,它将无法再使用,并且无法将其恢复到任何其他状态。

这意味着您需要重新创建MediaPlayer,从mediaPlayer = new MediaPlayer()或其中一个mediaPlayer.onCreate()方法开始。或者要注意何时调用release()

3

显然,Android MediaPlayer 的文档关于 reset() 没有无效状态是错误的。以下是我经历它时发生的情况:

在我的 PlayerActivity.java 代码中,我将我的 MediaPlayer 设为静态,以便我可以在我的主页 activity 中使用它:

public class PlayerActivity extends Activity {
....

public static MediaPlayer mp;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Mediaplayer
    if(mp == null) {
        mp = new MediaPlayer();
    }
    ....
}
/**
 * Function to play a song
 * @param songIndex - index of song
 * */
public void  playSong(int songIndex){
    // Play song
    try {
        if(mUpdateTimeTask != null)
            mHandler.removeCallbacks(mUpdateTimeTask);
        mp.reset();
            // the song path is get from internet
    mp.setDataSource(songsList.get(songIndex).get("songPath"));
    mp.prepareAsync();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
...
}

在我的家庭“活动”中,在关闭应用程序之前,我会释放播放器:
public class TuoiTreAppActivity extends TabActivity {
    ...

    @Override
    public void onDestroy(){
        if(PlayerActivity.mp != null) {
        PlayerActivity.mp.release();
        }   
        super.onDestroy();

    }
    ...

}

所以,当我第一次启动应用并开始播放音乐时,reset()函数可以正常运行,没有出现错误。但是当我点击返回按钮关闭应用程序并第二次启动它时,传递reset()函数时会出现IllegalStateException异常。
我在调试时也发现了原因。在第一次运行应用程序时,播放器为null,因此在PlayerActivity.javaonCreate()函数中进行初始化。但是,在应用程序关闭后,播放器未释放自己到null。因此,在第二次重新打开时不会再次初始化。这就是为什么在传递reset()函数时会出现IllegalStateException异常的原因。因此,要解决这个问题,我必须在关闭应用程序之前将播放器设置为null
@Override
public void onDestroy(){
    if(PlayerActivity.mp != null) {
        PlayerActivity.mp.release();
        // Set the MediaPlayer to null to avoid IlLegalStateException 
            // when call mp.reset() after launching the app again
        PlayerActivity.mp = null;
    }

    super.onDestroy();

}

1
两种情况会导致这种情况发生:
  1. 如前所述,如果在“release”后进行“reset”,则会出现错误,因为“release”将处理系统资源,因此“reset”是无效的命令。
  2. 如果您在“release”后尝试使用“mediaPlayer”对象,则也会收到异常。这是因为您需要重新创建对象并再次请求系统资源。

摆脱媒体播放器的正确顺序是释放它并将其设置为null。否则,您将有内存泄漏,因此这个顺序很重要

下面是一个快速示例:

    mediaPlayer.release();
    mediaPlayer = null;

当用户按下一个名为play的按钮时,您将需要重新创建媒体播放器:

public void createMediaPlayer() {
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
    mediaPlayer.setOnCompletionListener(callbackDelegate);
    mediaPlayer.setOnErrorListener(callbackDelegate);
    mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        public void onPrepared(MediaPlayer mp) {
            mediaPlayer.start();
        }
    });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接