android - studio - La superficie se ha liberado cuando intento configurarDisplay to MediaPlayer
mediaplayer permission android (6)
Mi archivo xml:
<SurfaceView
android:id="@+id/surfaceView"
android:layout_marginTop="50dp"
android:layout_width="fill_parent"
android:layout_height="300dp" />
Mi función para configurar Mostrar:
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();
}
}
el registro de la siguiente manera:
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)
He encontrado algunas preguntas similares aquí, pero todas esas no son adecuadas para mí. Esperando tus respuestas. Muchas gracias.
Es algo relacionado con la secuencia de ejecución, ya que la superficie debe crearse primero antes de configurar la visualización para el MediaPlayer
, por lo que debe anular la surfaceCreated
método de devolución de llamada.
@Override
public void surfaceCreated(SurfaceHolder holder) {
mp.setDisplay(sh); // now "mp" is defined as a class variable
}
y ahora no hay necesidad de configurarDisplay dentro de su método de juego:
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();
}
}
Hacer uso de SurfaceHolder.Callback como a continuación
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();
}
});
La forma más sencilla es llamar a setDisplay
en surfaceCreated
:
@Override
public void surfaceCreated(SurfaceHolder holder) {
mp.setDisplay(holder)
}
y no te olvides de desenlazar la superficie:
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mp.setDisplay(null);
}
Nota: el reproductor multimedia debe onCreate
en algún lugar antes, por ejemplo, en onCreate
.
La superficie puede ser destruida. Es por eso que necesita agregar a un public void surfaceDestroyed(SurfaceHolder holder)
a su implementación de SurfaceView de esta manera:
@Override public void surfaceDestroyed(SurfaceHolder holder) { synchronized (this) { hasActiveHolder = false; synchronized(this) { this.notifyAll(); } } }
También debe agregar una función que maneje la creación de Surface:
@Override public void surfaceCreated(SurfaceHolder holder) { synchronized (this) { hasActiveHolder = true; this.notifyAll() } }
Y modifica tu propia función de esta manera:
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();
}
Tienes otra opción que es la forma en que Google sugiere que uses SurfaceView: en un hilo separado.
Para aquellos que aún tienen problemas, intente implementar SurfaceHolder.Callback en su actividad / fragment / etc y en el método onCreate / onCreateView , llame al método addCallback (SurfaceHolder.Callback callback) , usando su actividad / fragment / etc como el parámetro callback.
Podemos ver el código fuente de VideoView:
SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback(){
...
public void surfaceCreated(SurfaceHolder holder)
{
mSurfaceHolder = holder;
openVideo();
}
private void openVideo() {
...
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDisplay(mSurfaceHolder);
}
}
Así que podemos aprender que debemos usar mediaplayer.setDisplay()
en el método surfaceCreate
.