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>