My xml file:
<SurfaceView
android:id="@+id/surfaceView"
android:layout_marginTop="50dp"
android:layout_width="fill_parent"
android:layout_height="300dp" />
My function to 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();
}
}
the log as below:
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)
I have found some similar questions here, but all of those are not suit for me. Waiting for your answers. Thanks very much.
The Surface can be destroyed. That's why you need to add to the a public void surfaceDestroyed(SurfaceHolder holder)
to your SurfaceView's implementation like this:
@Override public void surfaceDestroyed(SurfaceHolder holder) { synchronized (this) { hasActiveHolder = false; synchronized(this) { this.notifyAll(); } } }
You should also add a function that handles Surface creation:
@Override public void surfaceCreated(SurfaceHolder holder) { synchronized (this) { hasActiveHolder = true; this.notifyAll() } }
And modify your own function this way:
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();
}
You have another option which is the way Google suggests you use SurfaceView: in a separate thread.
It's something related to the sequence of executing, as the surface has to be created first before setting display for the MediaPlayer
, so you have to override the callback method surfaceCreated
to the following:
@Override
public void surfaceCreated(SurfaceHolder holder) {
mp.setDisplay(sh); // now "mp" is defined as a class variable
}
and now there is no need to setDisplay inside your play method:
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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With