Search code examples
androidexoplayer2.xandroid-viewpager2android-video-player

How to stop a video when the page is not visible in ViewPager2


I have a app where I make a API call and get a arraylist of videos, which I play in a viewpager using a adapter. When I scroll the viewpager, the video playing before still keeps playing and even after I scroll again. I want it so that the video should only play when the user is on that particular viewpager view and when user scrolls the video should stop.

Code for VideoAdapter class

public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoViewHolder> {

ArrayList<VideoModel> videos;

public VideoAdapter(ArrayList<VideoModel> videos) {
    this.videos = videos;
}

@NonNull
@Override
public VideoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.video_lyt,parent,false);
    return new VideoViewHolder(view);

}

@Override
public void onBindViewHolder(@NonNull VideoViewHolder holder, int position) {
holder.setData(videos.get(position));
}

@Override
public int getItemCount() {
    return videos.size();
}

class VideoViewHolder extends RecyclerView.ViewHolder {

    PlayerView playerview;
    TextView title,desc;
    SimpleExoPlayer simpleExoPlayer;

    public VideoViewHolder(@NonNull View itemView) {
        super(itemView);

        playerview = itemView.findViewById(R.id.playerView);
        title = itemView.findViewById(R.id.titleTextView);
        desc = itemView.findViewById(R.id.descTextView);
    }
    void setData(VideoModel videoModel)
    {
        Log.d("setting","data");
        simpleExoPlayer = new SimpleExoPlayer.Builder(itemView.getContext()).build();
        playerview.setPlayer(simpleExoPlayer);
        title.setText(videoModel.getUser_info().getTitle());
        desc.setText(videoModel.getDesc());
        MediaItem mediaItem = MediaItem.fromUri(videoModel.getUrl());
        simpleExoPlayer.setRepeatMode(Player.REPEAT_MODE_ONE);
        playerview.setUseController(false);
        //making the video fit the entire screen
        playerview.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL);
        simpleExoPlayer.setVideoScalingMode(C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
        simpleExoPlayer.addMediaItem(mediaItem);
        simpleExoPlayer.setPlayWhenReady(false);
        simpleExoPlayer.prepare();
    }
}

Code for MainActivity

public class MainActivity extends AppCompatActivity {

ViewPager2 viewPager2;
ArrayList<VideoModel> videos, videosSend;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
    viewPager2 = (ViewPager2) findViewById(R.id.viewpagerVideos);
    videos = new ArrayList<>();
    videosSend = new ArrayList<>();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("myapi")
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    APICall apiCall = retrofit.create(APICall.class);
    Call<VideoAPIData> call = apiCall.getVideos();
    call.enqueue(new Callback<VideoAPIData>() {
        @Override
        public void onResponse(Call<VideoAPIData> call, Response<VideoAPIData> response) {
            videos = response.body().getMsg();
            Log.d("API","Success");
            viewPager2.setAdapter(new VideoAdapter(videos));
        }
        @Override
        public void onFailure(Call<VideoAPIData> call, Throwable t) {
            Log.d("API Fail", t.getMessage());
        }
    });
}

Thanks to Nitish Chaudhary I have solved this issue

This is the updated Adapter class after the solution

public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoViewHolder> {

ArrayList<VideoModel> videos;
SimpleExoPlayer simpleExoPlayer;

public VideoAdapter(ArrayList<VideoModel> videos) {
    this.videos = videos;
}

@NonNull
@Override
public VideoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.video_lyt,parent,false);
    return new VideoViewHolder(view);

}

@Override
public void onBindViewHolder(@NonNull VideoViewHolder holder, int position) {
holder.setData(videos.get(position));
}

@Override
public int getItemCount() {
    return videos.size();
}

class VideoViewHolder extends RecyclerView.ViewHolder {

    PlayerView playerview;
    TextView title,desc;

    public VideoViewHolder(@NonNull View itemView) {
        super(itemView);

        playerview = itemView.findViewById(R.id.playerView);
        title = itemView.findViewById(R.id.titleTextView);
        desc = itemView.findViewById(R.id.descTextView);
    }
    void setData(VideoModel videoModel)
    {
        simpleExoPlayer = new SimpleExoPlayer.Builder(itemView.getContext()).build();
        playerview.setPlayer(simpleExoPlayer);
        title.setText(videoModel.getUser_info().getTitle());
        desc.setText(videoModel.getDesc());
        MediaItem mediaItem = MediaItem.fromUri(videoModel.getUrl());
        simpleExoPlayer.setRepeatMode(Player.REPEAT_MODE_ONE);
        playerview.setUseController(false);
        //making the video fit the entire screen
        playerview.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL);
        simpleExoPlayer.setVideoScalingMode(C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
        simpleExoPlayer.addMediaItem(mediaItem);
        
         //this code sets the playwhenready(true) for only the first video to be shown at the launch of app
        if(videoModel.getPlaying()!=null)
        {
            simpleExoPlayer.setPlayWhenReady(true);
        }
        else{
            simpleExoPlayer.setPlayWhenReady(false);
        }
        simpleExoPlayer.prepare();
    }
}

//this is the change that solves this issue

@Override
public void onViewAttachedToWindow(@NonNull VideoViewHolder holder) {
    super.onViewAttachedToWindow(holder);
    holder.playerview.getPlayer().setPlayWhenReady(true);
    holder.playerview.getPlayer().prepare();
}

@Override
public void onViewDetachedFromWindow(@NonNull VideoViewHolder holder) {
    super.onViewDetachedFromWindow(holder);
    holder.playerview.getPlayer().setPlayWhenReady(false);
    holder.playerview.getPlayer().stop();
}

}


Solution

  • You can override onViewAttachedToWindow and onViewDetachedFromWindow and play/pause your videos only when view is visible on the user.

    RecyclerAdapter

    public class VideoAdapter extends RecyclerView.Adapter {
    
    @Override
    @Override
    public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) {
        super.onViewAttachedToWindow(holder);
        //play video
    
    
    }
    
    @Override
    public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) {
        super.onViewDetachedFromWindow(holder);
        //pause video
    
     
    }