【问题标题】:The surface has been released when I try to setDisplay to MediaPlayer当我尝试将显示设置为 MediaPlayer 时,表面已被释放
【发布时间】:2013-04-18 04:16:47
【问题描述】:

我的 xml 文件:

<SurfaceView
    android:id="@+id/surfaceView"
    android:layout_marginTop="50dp"
    android:layout_width="fill_parent"
    android:layout_height="300dp" />

我的 setDisplay 函数:

public void playVideo() {
    MediaPlayer mp = new MediaPlayer();
    SurfaceView sv = (SurfaceView) this.findViewById(R.id.surfaceView);
    try {
        mp.setDataSource("sdcard/test/a.3gp");
        SurfaceHolder sh = sv.getHolder();
        mp.setDisplay(sh);***----the exception occured here***
        mp.prepare();
        mp.start();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

日志如下:

04-24 22:19:33.645: W/System.err(16106): java.lang.IllegalArgumentException: The surface has been released
04-24 22:19:33.645: W/System.err(16106):    at android.media.MediaPlayer._setVideoSurface(Native Method)
04-24 22:19:33.645: W/System.err(16106):    at android.media.MediaPlayer.setDisplay(MediaPlayer.java:698)

我在这里发现了一些类似的问题,但所有这些问题都不适合我。等待您的答复。非常感谢。

【问题讨论】:

    标签: android surfaceview android-mediaplayer


    【解决方案1】:

    表面可以被破坏。这就是为什么您需要像这样将 public void surfaceDestroyed(SurfaceHolder holder) 添加到 SurfaceView 的实现中:

      @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        synchronized (this) {
            hasActiveHolder = false;
    
            synchronized(this)          {
                  this.notifyAll(); 
            }
        } 
    }
    

    您还应该添加一个处理 Surface 创建的函数:

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
         synchronized (this) {
            hasActiveHolder = true;
            this.notifyAll()
         }
    }
    

    然后这样修改你自己的函数:

        mp.setDataSource("sdcard/test/a.3gp");
        SurfaceHolder sh = sv.getHolder();
        synchronized (this) {
           while (!hasActiveHolder) {
                  try {
                      this.wait();
                  } catch (InterruptedException e) {
                    //Print something
                  }
            }
            mp.setDisplay(sh);
            mp.prepare();
        }
    

    您还有另一种选择,即 Google 建议您使用 SurfaceView 的方式:在单独的线程中。

    【讨论】:

    • 你说的我试过了,还是不行,按住屏变黑了。等待您的更多信息。非常感谢您的回答。
    • 我刚刚注意到,在 surfaceDestroyed 中,我在同一个对象的同步块中放置了一个同步块。删除第二个。似乎你被困在等待中。我建议如果这不起作用,你附加一个调试器并暂停你看到的所有线程,以便找到哪个线程在 wait()
    • 我已经尝试了另一种方法来修复它。当表面被创建('surfaceCreated')时,我将'setDisplay'移动到回调。它完成了。非常感谢您的回答!
    【解决方案2】:

    这与执行的顺序有关,因为在为MediaPlayer设置显示之前必须先创建表面,因此您必须将回调方法surfaceCreated覆盖为以下内容:

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mp.setDisplay(sh); // now "mp" is defined as a class variable
    }
    

    现在不需要在你的播放方法中设置显示:

    private MediaPlayer mp; // to use it inside surfaceCreated callback method
    public void playVideo() {
        mp = new MediaPlayer();
        SurfaceView sv = (SurfaceView) this.findViewById(R.id.surfaceView);
        try {
            mp.setDataSource("sdcard/test/a.3gp");
            SurfaceHolder sh = sv.getHolder();
            mp.prepare();
            mp.start();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    

    【讨论】:

      【解决方案3】:

      使用 SurfaceHolder.Callback 如下

      SurfaceView mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
      SurfaceHolder holder = mSurfaceView.getHolder();
      final MediaPlayer player = new MediaPlayer();
      
      holder.addCallback(new SurfaceHolder.Callback() {
          @Override
          public void surfaceCreated(SurfaceHolder holder) {
              player.setDisplay(holder);
          }
      
          @Override
          public void surfaceChanged(SurfaceHolder holder, int format, int width, 
          int height) {
      
          }
      
          @Override
          public void surfaceDestroyed(SurfaceHolder holder) {
      
          }
      });
      
      String UrlPath="android.resource://"+getActivity().getPackageName()+"/"+R.raw.your_file_name_without_extension;
      try {
          player.setDataSource(getActivity(),Uri.parse(UrlPath));
          player.prepareAsync();
      } catch (IOException e) {
          e.printStackTrace();
      }
      player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
      
          @Override
          public void onPrepared(MediaPlayer mp) {
              mp.start();
          }
      });
      

      【讨论】:

        【解决方案4】:

        最简单的方法就是在surfaceCreated中调用setDisplay

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            mp.setDisplay(holder)
        }
        

        别忘了解除表面绑定:

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            mp.setDisplay(null);
        }
        

        注意:媒体播放器应该在之前的某个地方初始化,例如onCreate

        【讨论】:

          【解决方案5】:

          对于那些仍然有问题的人,请尝试在您的活动/片段/等中实现 SurfaceHolder.Callback 并在 onCreate/onCreateView 方法中调用 addCallback( SurfaceHolder.Callback callback)方法,使用你的activity/fragment/etc作为参数回调。

          【讨论】:

            【解决方案6】:

            我们可以看看VideoView源码:

            SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback(){
            ...
                public void surfaceCreated(SurfaceHolder holder)
                {
                    mSurfaceHolder = holder;
                    openVideo();
                }
                private void openVideo() {
                    ...
                    mMediaPlayer = new MediaPlayer();
                    mMediaPlayer.setDisplay(mSurfaceHolder);
                }
            }
            

            所以我们可以知道我们应该在surfaceCreate方法被调用时使用mediaplayer.setDisplay()

            【讨论】:

              猜你喜欢
              • 2012-06-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-04-04
              • 2014-01-06
              相关资源
              最近更新 更多