Issue
I'm trying to load a VAST ad using Exoplayer IMA extension (using tutorials 1, 2). I want to keep ad and content progress, so if app goes background or screen rotates, user continues from the point he/she was watching. You can see my code here and main codes below for convenience. (Duo to some limitations, I'm stuck with version 2.9.6 of Exoplayer library)
public class MainActivity extends AppCompatActivity {
private PlayerView playerView;
private SimpleExoPlayer player;
private static final String KEY_WINDOW = "window";
private int currentWindow;
private static final String KEY_POSITION = "position";
private long playbackPosition;
private static final String KEY_AUTO_PLAY = "auto_play";
private boolean playWhenReady;
private ImaAdsLoader adsLoader;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
playerView = findViewById(R.id.exo_video_view);
if (adsLoader == null)
adsLoader = new ImaAdsLoader(this, Uri.parse(getString(R.string.ad_tag_url)));
if (savedInstanceState != null) {
currentWindow = savedInstanceState.getInt(KEY_WINDOW);
playbackPosition = savedInstanceState.getLong(KEY_POSITION);
playWhenReady = savedInstanceState.getBoolean(KEY_AUTO_PLAY, true);
}
}
private MediaSource buildMediaSource(Uri uri, DataSource.Factory dataSourceFactory) {
return new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
}
private MediaSource buildAdMediaSource(MediaSource contentMediaSource, DataSource.Factory dataSourceFactory){
// Create the AdsMediaSource using the AdsLoader and the MediaSource.
return new AdsMediaSource(contentMediaSource, dataSourceFactory, adsLoader, playerView);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
private void initializePlayer() {
player = ExoPlayerFactory.newSimpleInstance(this);
playerView.setPlayer(player);
if (adsLoader != null)
adsLoader.setPlayer(player);
Uri contentUri = Uri.parse(getString(R.string.media_url_mp4));
DataSource.Factory dataSourceFactory =
new DefaultDataSourceFactory(this, "exoplayer-codelab");
MediaSource contentMediaSource = buildMediaSource(contentUri, dataSourceFactory);
MediaSource adMediaSource = buildAdMediaSource(contentMediaSource, dataSourceFactory);
player.setPlayWhenReady(playWhenReady);
player.seekTo(currentWindow, playbackPosition);
player.prepare(adMediaSource, false, false);
}
@Override
public void onStart() {
super.onStart();
if (Util.SDK_INT >= 24) {
initializePlayer();
if (playerView != null) {
playerView.onResume();
}
}
}
@Override
public void onResume() {
super.onResume();
hideSystemUi();
if ((Util.SDK_INT < 24 || player == null)) {
initializePlayer();
if (playerView != null) {
playerView.onResume();
}
}
}
private void hideSystemUi() {
playerView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
@Override
public void onPause() {
super.onPause();
if (Util.SDK_INT < 24) {
if (playerView != null) {
playerView.onPause();
}
releasePlayer();
}
}
@Override
public void onStop() {
super.onStop();
if (Util.SDK_INT >= 24) {
if (playerView != null) {
playerView.onPause();
}
releasePlayer();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
releaseAdsLoader();
}
private void releasePlayer() {
if (player != null) {
updateStartPosition();
player.release();
player = null;
}
if (adsLoader != null) {
adsLoader.setPlayer(null);
}
}
private void releaseAdsLoader() {
if (adsLoader != null) {
adsLoader.release();
adsLoader = null;
if (playerView.getOverlayFrameLayout() != null)
playerView.getOverlayFrameLayout().removeAllViews();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
updateStartPosition();
outState.putBoolean(KEY_AUTO_PLAY, playWhenReady);
outState.putInt(KEY_WINDOW, currentWindow);
outState.putLong(KEY_POSITION, playbackPosition);
}
private void updateStartPosition() {
if (player != null) {
playWhenReady = player.getPlayWhenReady();
currentWindow = player.getCurrentWindowIndex();
playbackPosition = Math.max(0, player.getContentPosition());
}
}
}
Problem is, when screen rotates, activity fields like ImaAdsLoader
becomes null and ad and content video play from start. I've saved player progress and can successfully restore it's position but that's not case for ImaAdsLoader
since I couldn't find a way to restore its state. Am I doing anything wrong? How Ad progress state should be saved and restored?
Solution
A common pattern with video players is to prevent your activity from being recreated with orientation changes so you should add these flags to your manifest.
android:configChanges="keyboardHidden|orientation|screenSize"
This would also prevent the surface view that shows your video from being destroyed with orientation changes too.
Answered By - oziomajnr
Answer Checked By - Timothy Miller (JavaFixing Admin)