5

解决这个问题对我来说有点困难,因为我是通过别人的安卓设备的崩溃报告得到的,我没有办法问他们问题,而且我从来没有在我自己的安卓设备上看到过这种情况。

崩溃报告说它是 Android 4.1.2,堆栈跟踪是:

java.lang.NullPointerException
at android.media.MediaPlayer$EventHandler.handleMessage(MediaPlayer.java:2102)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5021)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556)
at dalvik.system.NativeStart.main(Native Method)

不幸的是,grepcode.com 上的 android 源代码似乎与这些行号不匹配,所以我不确定哪个是空的。

我不知道发生这种情况时用户在做什么,所以我不知道这是在播放音乐或音效时发生的,还是在销毁时发生的。我有点怀疑它可能在销毁期间发生。我在活动的 onDestroy 方法中有以下代码:

public void onDestroy() {
    synchronized(curPlayers) {
        for(List<MediaP> ms : curPlayers.values()) {
            synchronized(ms) {
                for(MediaP m : ms) {
                    synchronized(m) {
                        m.m.stop();
                        m.m.release();
                    }
                }
            }
        }
        curPlayers.clear();
    }
}

private static class MediaP {
    private MediaP(MediaPlayer m) {
        this.m = m;
    }

    private MediaPlayer m;
    private boolean wasPlaying = false;
}

里面有什么我应该做的吗?

4

4 回答 4

5

删除对MediaPlayer.stop()之前的调用release()。我们在 Nexus 4、5、7、10 和 Moto X 上看到了很多类似的崩溃。您可以在此处阅读更多内容NullPointerException in MediaPlayer$EventHandler.handleMessage

据我了解,有一次他们切换到从 发送消息stop(),如果你够倒霉,你release()会在他们检查它不为空并尝试调用它的方法后立即取消一个对象。

于 2013-12-09T10:21:23.750 回答
2

Hank 和 Dmitry 的观点几乎是正确的,但最好使用组合方法。

竞争条件在内部 MediaPlayer 事件处理程序和 Android KitKat 和 Lollipop 版本上的 reset()/release() 之间。release() 使用所有事件处理程序(例如 onCompletion)创建竞争条件,而 reset() 仅具有播放状态消息的竞争。(start()、pause()、stop()、onCompletion()、onInfo() 也发布内部播放状态消息)。如果在 null 检查之后但在取消引用之前处理这些消息时调用了 reset()/release(),则会发生 NPE。

为避免这种情况,您可以:

  1. 永远不要调用 reset() 或 release()。这是不可接受的,因为必须释放每个 MediaPlayer 对象()。
  2. 仅从事件处理程序(例如 onCompletion、onError 等)调用 reset() 或 release()。这避免了比赛,但它本身是不可接受的,因为您可能需要在事件之外调用 reset()/release()。
  3. 在事件之外调用 reset()/release() 时,如果媒体播放器没有停止(例如播放或暂停)以触发内部消息和已知的稳定状态,则调用 stop(),然后在调用 release 之前等待一些例如 50 毫秒()。这基本上是汉克的建议。

最好的方法是 2 和 3 的组合。

于 2015-12-09T23:43:46.283 回答
1

代替

删除对MediaPlayer.stop()之前的调用release()

我添加了一个Thread.sleep(50)之前release()并解决了这个异常。似乎不仅stop()会被 的无效化所困扰release(),其他一些事件处理程序也OnCompletionListener有这个问题。

于 2015-05-25T04:04:54.143 回答
0

鉴于您的具体情况,我认为目标设备可能正在使用自制固件映像运行。

媒体播放器可能是定制的并且没有正确编程。

于 2013-08-14T06:27:50.270 回答