Черный экран при возврате к активности воспроизведения видео в Android

В настоящее время я разрабатываю приложение для Android ServeStream, с которым я столкнулся, и проблема, которую я не могу исправить. Мое приложение будет передавать музыку и видео с помощью класса android MediaPlayer. Я смоделировал свой класс после примера, найденного по адресу:

http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Video.html

Разница между этим примером и моим собственным кодом – это мой MediaPlayer, который запускается в службе, которая позволяет продолжить воспроизведение в фоновом режиме. Проблема с примером кода Android заключается в том, что если я просматриваю видео, и я покидаю текущее окно / активность (т. Е. Нажмите кнопку меню и т. Д.) И вернусь к активности воспроизведения, я получаю черный экран, но все же получаю аудио с видео Это игра.

Когда моя активность воспроизведения первоначально создается, выполняется код, показанный ниже. Этот код по существу создает представление, используемое для воспроизведения, а затем привязывает его к медиаплееру:

setContentView(R.layout.mediaplayer_2); mPreview = (SurfaceView) findViewById(R.id.surface); holder = mPreview.getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); ... mMediaPlayer.setDisplay(holder); 

Важной линией является mMediaPlayer.setDisplay (держатель), поскольку он связывает текущий просмотр / отображение с медиаплеером. Вид («держатель») уничтожается, когда вы покидаете действие. После возврата к активности и воссоздания представления, выполнение mMediaPlayer.setDisplay (владельца) снова не появляется, чтобы снова присоединить вновь созданное представление. Вместо видео отображается черный экран.

У кого-нибудь есть обходное решение или решение этой проблемы. Буду признателен за любую помощь или совет.

Solutions Collecting From Web of "Черный экран при возврате к активности воспроизведения видео в Android"

После многоголосного поиска и разбивания головы по диаграмме состояния MediaPlayer мне, наконец, удалось избежать этого так называемого черного экрана. Я уже опубликовал в разделе комментариев к OP, что эта проблема, по-видимому, решена с использованием последних версий Android (больше 4.x), и поэтому я предпочитаю иметь подобное поведение на устройствах Gingerbread.

Излишне говорить, SurfaceHolder методы обратного вызова SurfaceHolder играют очень важную роль на жизненном цикле ограниченной реализации MediaPlayerSurfaceView . И те самые методы обратного вызова пригодились мне для выхода из этой ситуации.

Первый:

In onCreate (): – Основная информация о инициализации ..

  mVideoSurface = (SurfaceView) findViewById(R.id.videoSurface); videoHolder = mVideoSurface.getHolder(); videoHolder.addCallback(this); // For Android 2.2 videoHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // Media Player and Controller player = new MediaPlayer(); controller = new VideoControllerView(this); 

Затем обратные вызовы SurfaceView:

Не забудьте установить Display на ваш MediaPlayer и IMHO, для этого surfaceCreated() .

 @Override public void surfaceCreated(SurfaceHolder holder) { player.setDisplay(holder); try { player.prepareAsync(); } catch (IllegalStateException e) { e.printStackTrace(); } } 

И вот самое главное. Когда пользователь покидает текущую активность, нажав кнопку «Главная» или открыв другое действие с ожиданием каких-либо результатов, наш SurfaceView будет уничтожен. Я хотел бы добиться возобновления воспроизведения текущего видео с позиции, в которой он играл, когда контекст переключился. Итак, чтобы сделать это,

Сохраните текущую позицию воспроизведения в переменной, чтобы мы могли использовать ее позже, чтобы искать наше воспроизведение в этой конкретной позиции. И еще один. Отпустите проклятый экземпляр MediaPlayer . Я попытался не выпускать экземпляр MediaPlayer и это воссоздание, но я продолжаю терпеть неудачу снова и снова. Итак, сделана точка.

 @Override public void surfaceDestroyed(SurfaceHolder holder) { if (player != null) { mCurrentVideoPosition = player.getCurrentPosition(); player.release(); player = null; } } 

Теперь, onPrepared () Инициализируйте любой MediaController здесь, если вам интересно. Проверьте, воспроизводилось ли видео, и поэтому ищите видео в этой позиции.

  @Override public void onPrepared(MediaPlayer mp) { controller.setMediaPlayer(this); controller.setAnchorView((FrameLayout) findViewById(R.id.videoSurfaceContainer)); player.start(); if (mCurrentVideoPosition != 0) { player.seekTo(mCurrentVideoPosition); player.start(); } } 

Наконец, чтобы воспроизвести видео:

  void playVideo(){ try { if (player == null) player = new MediaPlayer(); player.setAudioStreamType(AudioManager.STREAM_MUSIC); player.setDataSource("SOME_VIDEO_FILE.3gp"); player.setOnPreparedListener(this); player.setOnErrorListener(new OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { mp.reset(); return false; } }); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } 

И это все. Я знаю, что проблема не там с более новыми версиями, и все отлично, но … много GBs все еще там.

Кажется, я знаю причину проблемы. Кажется, что медиапланер инициализирует свою поверхность ТОЛЬКО, когда вы вызываете prepare / Async (). Если после этого вы измените поверхность, вы получите то, что у вас есть. Таким образом, решение было бы отключить стандартный жизненный цикл активности через android: configChanges = "orientation | keyboardHidden". Это предотвратит вашу активность от повторных посещений. В противном случае вам следует позвонить, чтобы подготовить каждый раз, когда вы воссоздаете владельца.

У меня такая же проблема!

Во время воспроизведения видео нажмите кнопку HOME, а затем верните приложение. Я вхожу:

 public void surfaceCreated(SurfaceHolder holder) { player.setDisplay(holder); playVideo(); } 

В playVideo() меня есть:

 private void playVideo() { if (extras.getString("video_path").equals("VIDEO_URI")) { showToast("Please, set the video URI in HelloAndroidActivity.java in onClick(View v) method"); } else { try { if (flag == 0) { player.setDataSource(extras.getString("video_path")); player.prepareAsync(); flag = 1; } else { player.start(); } } catch (IllegalArgumentException e) { showToast("Error while playing video"); Log.i(TAG, "========== IllegalArgumentException ==========="); e.printStackTrace(); } catch (IllegalStateException e) { showToast("Error while playing video"); Log.i(TAG, "========== IllegalStateException ==========="); e.printStackTrace(); } catch (IOException e) { showToast("Error while playing video. Please, check your network connection."); Log.i(TAG, "========== IOException ==========="); e.printStackTrace(); } } } 

И у меня чистый черный фон и слышу аудиопоток.

Я заметил, что если в первый раз запустить эту активность, если я не сделаю player.setDisplay(holder); У меня будет такое же поведение .

Проведя два дня, пытаясь решить эту проблему …

EDIT: Обратите внимание, что это решение не работает на устройствах 4.x – видео просто не появляется, только пустой экран, и я не мог заставить его работать.

Вот конечный автомат, который выполняет следующие действия:
1. играет короткую пару секунд видео /res/raw/anim_mp4.mp4 (процедура, инициированная методом onCreate ())
2. если пользователь нажимает кнопку «домой», а затем возвращается в приложение, он будет искать видео для начала позиции и немедленно приостанавливаться (процедура, инициированная методом onResume ())

 package com.test.video; import android.app.Activity; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.WindowManager; public class MediaPlayerActivity extends Activity implements OnCompletionListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnSeekCompleteListener, SurfaceHolder.Callback { private final int STATE_NOT_INITIALIZED = 0; private final int STATE_INITIALIZING = 1; private final int STATE_INITIALIZED = 2; private final int STATE_SEEKING = 3; private final int STATE_DELAYING = 4; private final int STATE_PLAYING = 5; private final int STATE_FINISHED = 6; private final int STATE_RESUMED = 7; private final int STATE_RESUMED_PREPARING = 8; private final int STATE_RESUMED_PREPARED = 9; private final int STATE_RESUMED_SEEKING = 10; private int state = STATE_NOT_INITIALIZED; private SurfaceView surface; private MediaPlayer player; private SurfaceHolder holder; @Override protected void onCreate(Bundle savedInstanceState) { Log.d(Constants.TAG, "onCreate()"); super.onCreate(savedInstanceState); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.mediaplayer); surface = (SurfaceView) findViewById(R.id.idSurface); holder = surface.getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } @Override protected void onStart() { Log.d(Constants.TAG, "onStart()"); super.onStart(); state(); } @Override protected void onResume() { Log.d(Constants.TAG, "onResume()"); super.onResume(); if (STATE_FINISHED == state) { state = STATE_RESUMED; state(); } } @Override protected void onDestroy() { Log.d(Constants.TAG, "onDestroy()"); super.onDestroy(); if (player != null) { player.release(); player = null; } } @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { Log.d(Constants.TAG, "surfaceChanged()"); } @Override public void surfaceCreated(SurfaceHolder arg0) { Log.d(Constants.TAG, "surfaceCreated()"); } @Override public void surfaceDestroyed(SurfaceHolder arg0) { Log.d(Constants.TAG, "surfaceDestroyed()"); } @Override public void onPrepared(MediaPlayer mp) { Log.d(Constants.TAG, "onPrepared()"); state(); } @Override public void onCompletion(MediaPlayer mp) { Log.d(Constants.TAG, "onCompletion()"); state(); } @Override public void onSeekComplete(MediaPlayer mediaplayer) { Log.d(Constants.TAG, "onSeekComplete()"); state(); } private class ResumeDelayed extends PlayDelayed { protected void onPostExecute(Void result) { Log.d(Constants.TAG, "ResumeDelayed.onPostExecute()"); state(); }; } private void initPlayer() { Log.d(Constants.TAG, "initPlayer()"); try { if (player == null) { player = new MediaPlayer(); player.setScreenOnWhilePlaying(true); } else { player.stop(); player.reset(); } String uri = "android.resource://" + getPackageName() + "/" + R.raw.anim_mp4; player.setDataSource(this, Uri.parse(uri)); player.setDisplay(holder); player.setAudioStreamType(AudioManager.STREAM_MUSIC); player.setOnPreparedListener(this); player.prepareAsync(); player.setOnCompletionListener(this); player.setOnSeekCompleteListener(this); } catch (Throwable t) { Log.e(Constants.TAG, "Exception in media prep", t); } } private class PlayDelayed extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... arg0) { try { Thread.sleep(1000); } catch (InterruptedException e) { Log.e(Constants.TAG, "Can't sleep", e); } return null; } protected void onPostExecute(Void result) { Log.d(Constants.TAG, "PlayDelayed.onPostExecute()"); initPlayer(); }; } private void state() { switch (state) { case STATE_NOT_INITIALIZED: state = STATE_INITIALIZING; initPlayer(); break; case STATE_INITIALIZING: state = STATE_INITIALIZED; new PlayDelayed().execute(); break; case STATE_INITIALIZED: state = STATE_SEEKING; player.start(); player.seekTo(0); break; case STATE_SEEKING: state = STATE_DELAYING; player.pause(); new ResumeDelayed().execute(); break; case STATE_DELAYING: state = STATE_PLAYING; player.start(); break; case STATE_PLAYING: state = STATE_FINISHED; break; case STATE_RESUMED: state = STATE_RESUMED_PREPARING; initPlayer(); break; case STATE_RESUMED_PREPARING: state = STATE_RESUMED_PREPARED; new PlayDelayed().execute(); break; case STATE_RESUMED_PREPARED: state = STATE_RESUMED_SEEKING; player.start(); player.seekTo(0); break; case STATE_RESUMED_SEEKING: state = STATE_FINISHED; player.pause(); break; default: break; } } 

Платформа mediaplayer.xml:

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/black" > <SurfaceView android:id="@+id/idSurface" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> 

AndroidManifest.xml выглядит так:

 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test.video" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="10" /> <application android:icon="@drawable/ic_launcher" android:theme="@android:style/Theme.Black.NoTitleBar" > <activity android:name=".MediaPlayerActivity" android:label="@string/app_name" android:screenOrientation="portrait" android:theme="@android:style/Theme.Black.NoTitleBar" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> 

Я видел ту же проблему, просто воспроизводя видео на моей Galaxy S3 и на Xoom Tablet. Я отключил ускорение аппаратного (HW) в настройках плеера и решил проблему. Я не разрабатываю Android, но надеюсь, что это приведет вас к решению. Возможно, вы можете переключить этот параметр на обходной путь. Устройство, которое я использую, возможно, не имеет ускорения HW.

Вы можете сделать: mMediaPlayer.setDisplay(null) когда surfaceDestroy и когда вы снова вводите видео setDisplay для mediaPlayer с новым surfaceHolder .
Помните, всегда ставьте этот код ниже внутри onStart , потому что, когда домашний нажат или заблокирует экран, он заставит `sufaceCreate 'запускаться с новым держателем. Просмотр будет воссоздан, вместо этого на экране появится черный экран

  holder = mPreview.getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 

Надеюсь, что эта помощь!

Вы хотите, чтобы активность не отображалась, когда вы возвращаетесь? Если да, вы можете просто использовать флаг

 i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 

Если вы хотите, чтобы ваши медиафайлы воспроизводились в фоновом режиме, я предлагаю вам использовать видео поверхность, поскольку это раздражало меня, играя в фоновом режиме, хотя я не хочу. Есть способы, но я надеюсь, что этот будет плодотворным для вас. http://www.brightec.co.uk/blog/custom-android-media-controller

Эта ссылка на самом деле предназначена для настройки медиа-контроллеров по вашему желанию, но по мере того, как я создал ее с собой, меня беспокоило как нажатия домашнего ключа, видео будет воспроизводиться в фоновом режиме.