私の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)
ここで同様の質問をいくつか見つけましたが、それらのすべてが私には適していません。あなたの答えを待っています。どうもありがとう。
表面は破壊される可能性があります。そのため、SurfaceViewの実装にpublic void surfaceDestroyed(SurfaceHolder holder)
を次のように追加する必要があります。
@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();
}
別のスレッドで、SurfaceViewを使用することをGoogleが提案する方法である別のオプションがあります。
MediaPlayer
の表示を設定する前にまずサーフェスを作成する必要があるため、コールバックメソッドsurfaceCreated
を次のようにオーバーライドする必要があるため、これは実行のシーケンスに関連しています。
@Override
public void surfaceCreated(SurfaceHolder holder) {
mp.setDisplay(sh); // now "mp" is defined as a class variable
}
そして今、あなたのplayメソッド内で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();
}
}
以下のように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();
}
});
最も簡単な方法は、setDisplay
でsurfaceCreated
を呼び出すだけです。
@Override
public void surfaceCreated(SurfaceHolder holder) {
mp.setDisplay(holder)
}
サーフェスのバインドを解除することを忘れないでください:
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mp.setDisplay(null);
}
注:メディアプレーヤーは、onCreate
などのように、どこかで初期化する必要があります。
問題が解決しない場合は、activity/fragment/etcにSurfaceHolder.Callbackを実装し、onCreate/onCreateViewメソッドでaddCallback(SurfaceHolder。コールバックコールバック)メソッド。パラメーターコールバックとしてアクティビティ/フラグメントなどを使用します。
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()
を使用する必要があることがわかります。