Exo player when changing video orientation starts from the beginning.

1

I've been trying to solve the problem for days and nothing .. I am trying to implement the ExoPlayer in an application where videos and instructions and cooking recipes come out. The video works normal and everything is fine but when I change the orientation the video starts from the beginning, not from the previous position. I have tried everything but I can not solve it. I'm going to give my source code, the Exo player is in the StepFragment Class. link

    
asked by Ahmed 10.08.2018 в 10:13
source

1 answer

3

You have a serious bug in the code that causes some devices to explode:

  

08-10 12: 17: 15,982 5130-5336 / com.example.ahmed.ibake E / rsC ++: RS CPP error (masked by previous error): Allocation creation failed       RS CPP error (masked by previous error): Allocation creation failed       RS CPP error (masked by previous error): Blur radius out of 0-25 pixel bound

In your styles.xml file, you have several properties of shadowRadius , you must set a shadowRadius less than or equal to 25px in a view, because otherwise this segmentation error will cause you . This is because RenderScript , more specifically ScriptIntrinsicBlur .

Regarding the problem of reproduction:

You are overwriting both the onStart method and the onResume , with several validations. This causes you to prepare several ExoPlayer at the same time on some devices. Both the onStart , onStop and onDetach must be eliminated. Just overwrite onPause and onResume to stop and resume the reproduction and onDestroy to clean the playback objects.

The problem when turning the screen happens in the parameters that you send in the ExoPlayer when preparing it, remember that when you turn the screen the configuration changes the device, causing the activity to be recreated and obviously the children of it.

According to official documentation in relation to the method prepare of ExoPlayer :

  

mediaSource - The MediaSource to play.

     

resetPosition - Should the playback position be reset to the   default position in the first Timeline.Window. If false, playback will   start from the position defined by Player.getCurrentWindowIndex () and   Player.getCurrentPosition ().

     

resetState - Whether the timeline, manifest, tracks and track   selections should be reset. Should be true unless the player is being   prepared to play the same media as it was playing previously (e.g.   playback failed and is being retried).

In your preparation method initializePlayer() of StepFragment you have the following:

simpleExoPlayer.prepare(mediaSource, true, false);

If you notice, the second parameter, which is resetPosition , is sending it in true when it should be false , since the documentation says that if you send it true , this initialized from the default position and not in the position defined in seekTo .

That said, your StepFragment.java should look like this:

package com.example.ahmed.ibake;


import android.databinding.DataBindingUtil;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import com.example.ahmed.ibake.Recipes.Steps;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.example.ahmed.ibake.databinding.FragmentStepBinding;
import com.google.android.exoplayer2.util.Util;


import icepick.Icepick;
import icepick.State;

public class StepFragment extends Fragment {

    public static final String KEY_STEP_OBJECT = "stepObject";


    @State
    Steps step;

    @State
    long currentPosition = 0;
    private static final String KEY_WINDOW = "window";
    private static final String PLAYER_POSITION = "position";
    private FragmentStepBinding binding;
    private SimpleExoPlayer simpleExoPlayer = null;
    private static final String KEY_AUTO_PLAY = "auto_play";

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        Icepick.restoreInstanceState(this, savedInstanceState);

        binding = DataBindingUtil.inflate(LayoutInflater.from(container.getContext()),
                R.layout.fragment_step, container, false);

        if (null != step.getVideoUrl() && !(TextUtils.isEmpty(step.getVideoUrl()))) {
            initializePlayer();
        } else {
            binding.expPlayer.setVisibility(View.GONE);
        }

        return binding.getRoot();
    }


    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {

        super.onActivityCreated(savedInstanceState);

        if (null != binding.tvShortDescriptionStep) {
            binding.tvShortDescriptionStep.setText(step.getShortDescription());
            binding.tvFullDescription.setText(step.getDescription());
        } else {

            ((AppCompatActivity) getActivity()).getSupportActionBar().hide();
            getActivity().getWindow().setFlags(
                    WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN
            );
        }
    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    public void onResume() {
        super.onResume();
        if (simpleExoPlayer == null) {
            initializePlayer();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        if(simpleExoPlayer != null) {
            currentPosition = simpleExoPlayer.getCurrentPosition();
            simpleExoPlayer.release();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (simpleExoPlayer != null) {
            simpleExoPlayer.stop();
            simpleExoPlayer.release();
            simpleExoPlayer = null;
        }
    }


    @Override
    public void onSaveInstanceState(Bundle outState) {

        if (null != simpleExoPlayer) {
            simpleExoPlayer.setPlayWhenReady(true);
            currentPosition = simpleExoPlayer.getCurrentPosition();
            outState.putLong(PLAYER_POSITION, currentPosition);
            outState.putBoolean("state", simpleExoPlayer.getPlayWhenReady());
        }

        Icepick.saveInstanceState(this, outState);
        super.onSaveInstanceState(outState);

    }

    public void setStep(Steps step) {
        this.step = step;
    }

    public void updateStep(Steps step) {

        if (null != binding.tvShortDescriptionStep) {
            binding.tvShortDescriptionStep.setText(step.getShortDescription());
            binding.tvFullDescription.setText(step.getDescription());
        }

        if (null == simpleExoPlayer) {
            initializePlayer();
        }
        simpleExoPlayer.setPlayWhenReady(false);


        if (null != step.getVideoUrl() && !(TextUtils.isEmpty(step.getVideoUrl()))) {

            binding.expPlayer.setVisibility(View.VISIBLE);
            Uri uri = Uri.parse(step.getVideoUrl());
            MediaSource mediaSource = buildMediaSource(uri);
            simpleExoPlayer.prepare(mediaSource, true, false);
            simpleExoPlayer.setPlayWhenReady(true);

        } else {
            binding.expPlayer.setVisibility(View.GONE);
        }
    }

    private MediaSource buildMediaSource(Uri uri) {
        return new ExtractorMediaSource(uri,
                new DefaultHttpDataSourceFactory("ua"),
                new DefaultExtractorsFactory(), null, null);
    }

    private void initializePlayer() {

        simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(
                new DefaultRenderersFactory(getContext()),
                new DefaultTrackSelector(),
                new DefaultLoadControl());

        binding.expPlayer.setPlayer(simpleExoPlayer);
        simpleExoPlayer.seekTo(currentPosition);
        simpleExoPlayer.setPlayWhenReady(true);

        Uri uri = Uri.parse(step.getVideoUrl());
        MediaSource mediaSource = buildMediaSource(uri);
        simpleExoPlayer.prepare(mediaSource, false, false);
    }

}

and in your AndroidManifest.xml you must specify the configChanges to prevent the re-creation of the Activity handled by the player, in this case StepActivity :

<activity android:name=".StepActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"/>

To make visual changes manually by changing the settings, for example, set the video in FullScreenMode , add the method overwritten in StepFragment :

    @Override
        public void onConfigurationChanged(Configuration newConfig) {

            super.onConfigurationChanged(newConfig);
            int currentOrientation = getResources().getConfiguration().orientation;
            // Si es landscape, cambia los valores visuales
            if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE){
             // Ocultar la barra de estado
                getActivity().getWindow()
                .getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);

            // Ocultar la barra de accion
            if(((AppCompatActivity)getActivity()).getSupportActionBar() != null)
                ((AppCompatActivity)getActivity()).getSupportActionBar().hide();

                binding.expPlayer.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            }
            else {
                // Mostrar la barra de estado
                getActivity().getWindow()
                .getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

                // Mostrar la barra de accion
                if(((AppCompatActivity)getActivity()).getSupportActionBar() != null)
                    ((AppCompatActivity)getActivity()).getSupportActionBar().show();

                binding.expPlayer.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200, getResources().getDisplayMetrics())));

            }
        }

When you put it in FullScreen mode you must do a resize of the Layout so you must add the following property to the root of the Layout:

android:fitsSystemWindows="true" , your axml code should look like this:

fragment_step.axml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <com.google.android.exoplayer2.ui.SimpleExoPlayerView
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:id="@+id/exp_player"
            app:resize_mode="fixed_height"
            app:auto_show="false"
            />

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/exp_player"
            >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            >

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/tv_short_description_step"
                android:textSize="24sp"
                android:textColor="@color/ingre_qty_text"
                android:layout_marginStart="16dp"
                android:layout_marginEnd="16dp"
                android:layout_marginTop="16dp"
                tools:text="This will show the short description of the text."
                />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/tv_full_description"
                android:textSize="20sp"
                android:textColor="@color/ingre_qty_text"
                android:layout_marginStart="16dp"
                android:layout_marginEnd="16dp"
                android:layout_marginTop="16dp"
                tools:text="This will show the full description of the text."
                />

        </LinearLayout>

        </ScrollView>

    </RelativeLayout>

</layout>
    
answered by 10.08.2018 / 18:53
source