2013-04-24 52 views
13

表面已被釋放,當我嘗試我的XML文件setDisplay到MediaPlayer的

<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) 

我在這裏發現了一些類似的問題,但所有這些都不適合我。等待你的答案。非常感謝。

回答

12

表面可能被破壞。這就是爲什麼你需要添加到一個public void surfaceDestroyed(SurfaceHolder holder)您SurfaceView的實現是這樣的:

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

     synchronized(this)   { 
       this.notifyAll(); 
     } 
    } 
} 

你也應該補充的是處理表面建立一個功能:

@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:在單獨的線程中。

+1

我試過了你說的,但它不起作用,屏幕變成黑色。等待你的更多信息。非常感謝您的回答。 – Cooosuper 2013-04-25 01:50:39

+0

我只注意到在surfaceDestroyed中,我在同一個對象的同步塊中放置了同步。刪除第二個。看起來你似乎在等待。我建議如果這不起作用,你附加一個調試器,並暫停你看到的所有線程,以便找到哪個線程正在等待() – EyalBellisha 2013-04-25 15:05:53

+3

我已經嘗試了另一種方法來解決它。我將'setDisplay'移動到回調時表面被創建('surfaceCreated')。它完成了。非常感謝您的回答! – Cooosuper 2013-04-26 01:50:01

8

這件事情關係到執行的順序,因爲表面必須爲MediaPlayer, so you have to override the callback method surfaceCreated`設置顯示以下之前,首先創建:

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

,現在也沒有必要裏面setDisplay您遊戲方法:

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(); 
    } 
} 
0

最簡單的方法是隻爲了呼喚setDisplaysurfaceCreated

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

,不要忘記解除綁定面:

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

注:媒體播放器應該在onCreate在什麼地方初始化,例如。

1

對於那些仍然有問題,嘗試在活動/片段/等,並在的onCreate/onCreateView方法實現SurfaceHolder.Callback,調用的addCallback(SurfaceHolder.Callback回調)方法,使用您的activity/fragment /等作爲參數回調。

0

使用SurfaceHolder。回調如下

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(); 
    } 
}); 
0

我們可以看看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()被調用。

相關問題