I want to implement a RecyclerView that works similar to Instagram feeds, that contains both Image and Video Items. I have successful implemented the recyclerView to display both image and video items, but I am having issues with pausing the video items when the onScrollListener is on RecyclerView.SCROLL_STATE_DRAGGING
I am using ExoPlayer library for the video player"
So, if a video is played and the recyclerView is not pause it keeps on playing that video even if another video is played from the list. Making multiple video playing at the same time.
Below is my implementation Adapter
public class RecyclerAdapter extends RecyclerView.Adapter {
private ArrayList<ListModel> listModelList;
private Context context;
SimpleExoPlayer exoPlayer;
public RecyclerAdapter(ArrayList<ListModel> listModelList, Context context) {
this.listModelList = listModelList;
this.context = context;
}
@Override
public int getItemViewType(int position) {
if (listModelList.get(position).getDescription().equalsIgnoreCase("video")) {
return 1;
} else {
return 0;
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view;
if (viewType == 0) {
view = inflater.inflate(R.layout.recycler_item, parent, false);
return new AdsViewHolder(view);
} else {
view = inflater.inflate(R.layout.video_item, parent, false);
return new VideoVH(view);
}
}
@Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
ListModel listModel = listModelList.get(position);
if (listModel.getDescription().equalsIgnoreCase("video")) {
VideoVH videoVH = (VideoVH) holder;
initPlayer(((VideoVH) holder).playerView, listModel.getMedia_url(), ((VideoVH) holder).progressBar);
((VideoVH) holder).titleText.setText(listModel.getTitle());
((VideoVH) holder).descText.setText(listModel.getDescription());
//Play video
} else {
AdsViewHolder adsViewHolder = (AdsViewHolder) holder;
((AdsViewHolder) holder).titleText.setText(listModel.getTitle());
((AdsViewHolder) holder).descText.setText(listModel.getDescription());
Glide.with(context)
.load(listModel.getMedia_url())
.into(((AdsViewHolder) holder).imageView);
}
}
private void initPlayer(final PlayerView playerView, String uri, final ProgressBar progressBar) {
TrackSelector trackSelector = new DefaultTrackSelector();
exoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
playerView.setPlayer(exoPlayer);
exoPlayer.setPlayWhenReady(false);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context, Util.getUserAgent(context, "ExoRecyclerView"));
MediaSource videoSource = new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(uri));
exoPlayer.prepare(videoSource);
playerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL);
exoPlayer.setVideoScalingMode(C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
exoPlayer.seekTo(500);
exoPlayer.addListener(new Player.EventListener() {
@Override
public void onTimelineChanged(Timeline timeline, @Nullable Object manifest, int reason) {
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
@Override
public void onLoadingChanged(boolean isLoading) {
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
switch (playbackState) {
case Player.STATE_BUFFERING:
// Log.e(TAG, "onPlayerStateChanged: Buffering video.");
if (progressBar != null) {
progressBar.setVisibility(VISIBLE);
}
break;
case Player.STATE_ENDED:
break;
case Player.STATE_IDLE:
break;
case Player.STATE_READY:
// Log.e(TAG, "onPlayerStateChanged: Ready to play.");
if (progressBar != null) {
progressBar.setVisibility(GONE);
}
break;
default:
break;
}
}
@Override
public void onRepeatModeChanged(int repeatMode) {
}
@Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
@Override
public void onPlayerError(ExoPlaybackException error) {
}
@Override
public void onPositionDiscontinuity(int reason) {
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
@Override
public void onSeekProcessed() {
}
});
}
@Override
public int getItemCount() {
return listModelList.size();
}
class AdsViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
TextView titleText, descText;
public AdsViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.thumbnail);
descText = itemView.findViewById(R.id.desc);
titleText = itemView.findViewById(R.id.title);
}
}
class VideoVH extends RecyclerView.ViewHolder {
PlayerView playerView;
TextView titleText, descText;
ConstraintLayout VV;
ProgressBar progressBar;
ImageView volumeControl;
public VideoVH(@NonNull View itemView) {
super(itemView);
playerView = itemView.findViewById(R.id.playerView);
descText = itemView.findViewById(R.id.desc);
titleText = itemView.findViewById(R.id.title);
volumeControl = itemView.findViewById(R.id.volume_control);
VV = itemView.findViewById(R.id.parent);
progressBar = itemView.findViewById(R.id.progressBar);
}
}
}
MainActivity imoplementation
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
ArrayList<ListModel> listModelList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.recyclerView);
ListModel listModel = new ListModel();
listModelList.add(new ListModel("One test",
"https://res.cloudinary.com/dqrs5xew4/image/upload/v1591991924/sample.jpg", "image"));
listModelList.add(new ListModel("One test",
"https://res.cloudinary.com/dqrs5xew4/video/upload/v1595538345/HNG/b5bc3f170b7d5c388410bcca0a501ecd_lnhzwn.mp4", "video"));
listModelList.add(new ListModel("One test",
"https://res.cloudinary.com/dqrs5xew4/image/upload/v1591991924/sample.jpg", "image"));
listModelList.add(new ListModel("One test",
"https://res.cloudinary.com/dqrs5xew4/video/upload/v1595538331/HNG/VID-20180713-WA0009_esbmff.mp4", "video"));
listModelList.add(new ListModel("One test",
"https://res.cloudinary.com/dqrs5xew4/image/upload/v1591991924/sample.jpg", "image"));
initRecyclerView();
}
private void initRecyclerView() {
// use a linear layout manager
LinearLayoutManager layoutManager =
new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
RecyclerAdapter mAdapter = new RecyclerAdapter(listModelList, MainActivity.this);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
}
}
Model Class
public class ListModel {
private String title;
private String media_url;
private String description;
public ListModel(String title, String media_url, String description) {
this.title = title;
this.media_url = media_url;
this.description = description;
}
public ListModel() {
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getMedia_url() {
return media_url;
}
public void setMedia_url(String media_url) {
this.media_url = media_url;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
I have gone through several question here and on youtube, But they all implemeted just a single view type in the recyclerView.
Any suggestion how I could control the Video Player when the recyclerView is been scrolled? Or a better way I could implement the Instagram feeds like RecyclerView