Android &引用;“表面已被释放”;“内部”;“表面处理”;

Android &引用;“表面已被释放”;“内部”;“表面处理”;,android,android-mediaplayer,surfaceholder,Android,Android Mediaplayer,Surfaceholder,我知道这是一个常见的问题,但是这个堆栈跟踪显示出其他问题。您可以看到,即使在surfaceCreated的内部调用了setDisplay(holder),它仍然抛出IllegalArgumentException。这也不是罕见的例外,昨天在约300万个剪辑视图中发生了约125000次。我可以向您保证,mCurrentPlayer也已正确初始化 表面处理: @Override public void surfaceCreated(SurfaceHolder holder) { mIsSur

我知道这是一个常见的问题,但是这个堆栈跟踪显示出其他问题。您可以看到,即使在
surfaceCreated
的内部调用了
setDisplay(holder)
,它仍然抛出
IllegalArgumentException
。这也不是罕见的例外,昨天在约300万个剪辑视图中发生了约125000次。我可以向您保证,
mCurrentPlayer
也已正确初始化

表面处理:

@Override
public void surfaceCreated(SurfaceHolder holder) {
    mIsSurfaceCreated = true;
    mCurrentPlayer.setDisplay(holder);
}
表面处理:

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    mIsSurfaceCreated = false;

    // Could be called after player was released in onDestroy.
    if (mCurrentPlayer != null) {
        mCurrentPlayer.setDisplay(null);
    }
}
堆栈跟踪:

java.lang.IllegalArgumentException: The surface has been released
    at android.media.MediaPlayer._setVideoSurface(Native Method)
    at android.media.MediaPlayer.setDisplay(MediaPlayer.java:660)
    at com.xxx.xxx.view.VideoPlayerView.surfaceCreated(VideoPlayerView.java:464)
    at android.view.SurfaceView.updateWindow(SurfaceView.java:543)
    at android.view.SurfaceView.access$000(SurfaceView.java:81)
    at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:169)
    at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:590)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1644)
    at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2505)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:4945)
    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:784)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
    at dalvik.system.NativeStart.main(Native Method)
你知道还有什么问题吗?
SurfaceHolder
是否可能破坏后台线程上的表面,然后等待主线程(当前由
surfaceCreated
占用)完成其块,然后才能调用主线程上的
surfaceDestroyed
(我甚至认为锁无法修复)?还有别的吗

更新——在进一步深入研究之后,我发现是什么导致“表面已被释放”:

哪些引用了android\u view\u Surface\u getSurface,可以找到:


<>这是我缺乏C++知识的地方,它看起来像是试图锁定在表面上,如果它不能返回的表面将是<代码> null <代码>。一旦返回为
null
,就会抛出
IllegalArgumentException

我以前使用Android VideoView/MediaPlayer时遇到过类似的问题。原来底层的SurfaceView正在被垃圾收集。我通过向MediaPlayer添加一个onPreparedLister来解决这个问题,然后在我使用它的时候在我的类中保持对它的显式引用。也许这会有帮助。

我刚刚解决了一个类似的问题

我的调查显示,SurfaceView中有一个bug,它导致将无效的surface传递给surfaceCreated回调方法

这是修复它的android repo中的提交:

android源代码中的补丁似乎是在4.2版本中引入的。而且,从应用程序的崩溃中,我看到由无效表面引起的崩溃只发生在4.0和4.1上

因此,我可以假设在4.0之前,将无效曲面传递给MediaPlayer是有效的。在4.0版本中,SurfaceView/MediaPlayer的逻辑发生了变化,导致其不再有效。但SurfaceView中的代码在4.2版本之前没有更新(在4.2版本中,SurfaceView中的此问题已得到修复)

我已经检查了android的git repo,实际上,版本标记的android-4.0.1_r1不包括补丁,版本标记的android-4.2.1_r1包括补丁

因此,要在不包含修复的平台上修复它,在将其设置为MediaPlayer之前,手动检查surface是否有效,仅在平台4.0及之后才需要:

@Override public void surfaceCreated(final SurfaceHolder holder) {
    final Surface surface = holder.getSurface();

    if ( surface == null ) return;

    // on pre Ice Scream Sandwich (4.0) versions invalid surfaces seems to be accepted (or at least do not cause crash)
    final boolean invalidSurfaceAccepted = Build.VERSION.SDK_INT < Build.ICE_CREAM_SANDWICH;
    final boolean invalidSurface = ! surface.isValid();

    if ( invalidSurface && ( ! invalidSurfaceAccepted ) ) return;

    _mediaPlayer.setDisplay(holder);
}
@覆盖已创建的公共无效表面(最终表面所有者){
最终曲面=holder.getSurface();
if(surface==null)返回;
//在冰上尖叫三明治(4.0)之前的版本中,似乎可以接受无效表面(或者至少不会导致碰撞)
最终布尔值invalidSurfaceAccepted=Build.VERSION.SDK\u INT

这样,在较旧的平台上,invalid surface将成功设置为媒体播放器,视频将播放,在平台4.0-4.1上,它将丢弃无效曲面(我认为将使用valid surface再次调用surfaceCreated)在4.2及更高版本上,surfaceCreated将不会使用无效的surface调用。

您是否在后台线程上进行渲染?您对surfaceDestroyed的实现是什么?(请注意,surfaceDestroyed的文档中说:“如果您有一个直接访问曲面的渲染线程,则必须确保该线程在从该函数返回之前不再接触曲面。”)没有背景渲染,
surface
仅由
MediaPlayer
用于显示视频。一旦调用
mp.setDisplay(surface)
,我就不接触表面。我也用SurfacedStroyed更新了我的帖子。请注意,根据android_media_MediaPlayer.cpp,如果
jsurface
null
则不会引发此异常。您可以共享该项目吗?问题很可能不在您显示的代码中,而是在应用程序的其他部分。当手机从锁定状态返回时是否可能出现问题?我过去使用Android VideoViews/MediaPlayer时遇到过类似的问题。原来底层的SurfaceView正在被垃圾收集。我通过向MediaPlayer添加一个onPreparedLister来解决这个问题,然后在我使用它的时候在我的类中保持对它的显式引用。也许这会有帮助。这就是我修复它的原因。我不知道为什么那些东西会被气相色变。很高兴这些小时的痛苦帮助了别人!你可以知道你的努力帮助了不止一个人。这也是我的问题。谢谢。如果曲面无效,您将采取什么措施
surfaceCreated
将不再被调用,因此您是否只需删除
SurfaceView
并重新添加它,希望创建的
Surface
第二次有效?不幸的是,我没有办法重现此问题,只有crashlogs,所以我唯一能做的就是防止崩溃——我没有可能测试它在不同的“修复”情况下的表现。也许这些关于问题原因的信息会对某些人有用。我已经用更多的细节和更有用的解决方案更新了我的答案。我的崩溃日志似乎反映出修复是在Android版本4.1.2中进行的。我在版本4.0.3、4.0.4和4.1.1上发现了250万个异常,但是4.1.2和4.1.2上没有一个异常是我们应用程序中使用最多的操作系统版本。然而,这是一个很好的调查信息