简体   繁体   English

android MediaPlayer NullPointerException

[英]android MediaPlayer NullPointerException

It's a bit difficult for me to troubleshoot this because I'm getting this via a crash report from someone else's android device, I have no way to ask them questions, and I've never seen it happen on my own android devices. 我有点难以对此进行故障排除,因为我是通过其他人的Android设备的崩溃报告得到的,我无法向他们提问,而且我从未在自己的Android设备上看到它。

The crash reports says it's Android 4.1.2 and the stack trace is: 崩溃报告说它是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)

Unfortunately the android source code at grepcode.com doesn't seem to match up with those line numbers, so I'm not sure which thing is null. 不幸的是,grepcode.com上的android源代码似乎与这些行号不匹配,所以我不确定哪个是null。

I don't know what the user was doing when this happens, so I don't know if this happens while music or sound effects are playing or if it happens on destroy or what. 当发生这种情况时,我不知道用户正在做什么,所以我不知道这是在音乐或声音效果正在播放时发生,还是在发生破坏时发生了什么。 I sort of suspect that it may happen during destroy. 我有点怀疑它可能在毁灭期间发生。 I have the following code in the activity's onDestroy method: 我在activity的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;
}

Is there something in there that I should be doing? 那里有什么我应该做的吗?

Remove a call to MediaPlayer.stop() before release() . release()之前删除对MediaPlayer.stop()的调用。 We have seen a lot of similar crashes on Nexus 4, 5, 7, 10 and Moto X. You can read more here NullPointerException in MediaPlayer$EventHandler.handleMessage 我们在Nexus 4,5,7,10和Moto X上看到了很多类似的崩溃。你可以在MediaPlayer $ EventHandler.handleMessage中阅读更多NullPointerException

As far as I understand, at one point they switched to sending messages from stop() , and if you get unlucky enough, your release() will nullify an object right after they check that it is not null and try to call its method. 据我所知,有一次他们切换到从stop()发送消息,如果你不够运气,你的release()会在检查到它不为空并尝试调用其方法后立即使对象无效。

Hank and Dmitry have this almost right, but it's best to use a combined approach. 汉克和德米特里几乎没有这个,但最好采用综合方法。

The race condition is between the internal MediaPlayer event handler and reset()/release() on Android KitKat and Lollipop releases. 竞争条件介于Android KitKat和Lollipop版本上的内部MediaPlayer事件处理程序和reset()/ release()之间。 release() creates a race condition with all event handlers (eg onCompletion), while reset() only has a race with playback state messages. release()使用所有事件处理程序(例如onCompletion)创建竞争条件,而reset()仅具有回放状态消息的竞争。 (start(), pause(), stop(), onCompletion(), onInfo() also post internal playback state messages). (start(),pause(),stop(),onCompletion(),onInfo()也发布内部回放状态消息)。 The NPE happens if reset()/release() is called while handling these message after the null checks but before the dereference. 如果在空检查之后但在取消引用之前处理这些消息时调用了reset()/ release(),则会发生NPE。

To avoid this, you could: 为避免这种情况,您可以:

  1. never call reset() or release(). 永远不要调用reset()或release()。 This is not acceptable as each MediaPlayer object must be released(). 这是不可接受的,因为必须释放每个MediaPlayer对象()。
  2. only call reset() or release() from an event handler (eg onCompletion, onError, etc.). 只从事件处理程序调用reset()或release()(例如onCompletion,onError等)。 This avoids the race, but is not acceptable by itself as you may need to call reset()/release() outside of an event. 这可以避免竞争,但是它本身是不可接受的,因为您可能需要在事件之外调用reset()/ release()。
  3. When calling reset()/release() outside of an event, call stop() if the media player is not stopped (eg playing or paused) to trigger the internal message and a known steady state, then wait some eg 50msec before calling release(). 在事件之外调用reset()/ release()时,如果媒体播放器没有停止(例如播放或暂停)以调用内部消息和已知的稳定状态,则调用stop(),然后等待一些例如50毫秒,然后再调用release ()。 This is basically Hank's suggestion. 这基本上是汉克的建议。

The best approach is a combination of 2 and 3. 最好的方法是2和3的组合。

Instead of 代替

Remove a call to MediaPlayer.stop() before release() release()之前删除对MediaPlayer.stop()的调用

I add a Thread.sleep(50) before release() and resolve this exception. 我在release()之前添加了一个Thread.sleep(50) release()并解决了这个异常。 It seems not only stop() will be bothered by the nullifying of release() , some other event handlers like OnCompletionListener have this problem too. 似乎不仅stop()会被release()的无效所困扰,其他一些像OnCompletionListener这样的事件处理程序也会OnCompletionListener这个问题。

Given your specific situation, I think the target device might be running with a self-made firmware image. 鉴于您的具体情况,我认为目标设备可能正在运行自制的固件映像。

The media player might be customized and not correctly programmed. 媒体播放器可能是自定义的,未正确编程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM