I have a video feed (similar to TikTok) but when I swipe up the new video plays but the old one keeps playing. I've managed to get a page listener but I cannot control the ExoPlayer from the "Home Fragment".
Any idea on how to trigger something inside the RecyclerView Adapter from the Home Fragment?
If there's a better solution for doing this, please tell me.
Home Fragment
public class HomeFragment extends Fragment {
private View view;
RecyclerView recyclerView;
List<Model> models = new ArrayList<>();
MainRecylerAdapter adapter;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_home, container, false);
recyclerView = view.findViewById(R.id.recyclerview);
models.add(new Model(1, "https://www.newslistener.com/Mukesh/1.mp4", "one"));
models.add(new Model(2, "https://www.newslistener.com/Mukesh/2.mp4", "one"));
models.add(new Model(3, "https://www.newslistener.com/Mukesh/3.mp4", "one"));
models.add(new Model(4, "https://www.newslistener.com/Mukesh/4.mp4", "one"));
models.add(new Model(5, "https://www.newslistener.com/Mukesh/5.mp4", "one"));
models.add(new Model(6, "https://www.newslistener.com/Mukesh/6.mp4", "one"));
models.add(new Model(7, "https://www.newslistener.com/Mukesh/7.mp4", "one"));
models.add(new Model(8, "https://www.newslistener.com/Mukesh/8.mp4", "one"));
models.add(new Model(9, "https://www.newslistener.com/Mukesh/9.mp4", "one"));
models.add(new Model(10, "https://www.newslistener.com/Mukesh/10.mp4", "one"));
models.add(new Model(11, "https://www.newslistener.com/Mukesh/11.mp4", "one"));
models.add(new Model(12, "https://www.newslistener.com/Mukesh/12.mp4", "one"));
models.add(new Model(13, "https://www.newslistener.com/Mukesh/13.mp4", "one"));
models.add(new Model(14, "https://www.newslistener.com/Mukesh/14.mp4", "one"));
models.add(new Model(15, "https://www.newslistener.com/Mukesh/15.mp4", "one"));
models.add(new Model(16, "https://www.newslistener.com/Mukesh/16.mp4", "one"));
models.add(new Model(17, "https://www.newslistener.com/Mukesh/17.mp4", "one"));
models.add(new Model(18, "https://www.newslistener.com/Mukesh/18.mp4", "one"));
models.add(new Model(19, "https://www.newslistener.com/Mukesh/19.mp4", "one"));
models.add(new Model(20, "https://www.newslistener.com/Mukesh/20.mp4", "one"));
models.add(new Model(21, "https://www.newslistener.com/Mukesh/21.mp4", "one"));
models.add(new Model(22, "https://www.newslistener.com/Mukesh/22.mp4", "one"));
models.add(new Model(23, "https://www.newslistener.com/Mukesh/23.mp4", "one"));
models.add(new Model(24, "https://www.newslistener.com/Mukesh/24.mp4", "one"));
models.add(new Model(25, "https://www.newslistener.com/Mukesh/25.mp4", "one"));
models.add(new Model(26, "https://www.newslistener.com/Mukesh/26.mp4", "one"));
models.add(new Model(27, "https://www.newslistener.com/Mukesh/27.mp4", "one"));
models.add(new Model(28, "https://www.newslistener.com/Mukesh/28.mp4", "one"));
models.add(new Model(29, "https://www.newslistener.com/Mukesh/29.mp4", "one"));
models.add(new Model(30, "https://www.newslistener.com/Mukesh/30.mp4", "one"));
models.add(new Model(31, "https://www.newslistener.com/Mukesh/31.mp4", "one"));
models.add(new Model(32, "https://www.newslistener.com/Mukesh/32.mp4", "one"));
models.add(new Model(33, "https://www.newslistener.com/Mukesh/33.mp4", "one"));
models.add(new Model(34, "https://www.newslistener.com/Mukesh/34.mp4", "one"));
models.add(new Model(35, "https://www.newslistener.com/Mukesh/35.mp4", "one"));
SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
adapter = new MainRecylerAdapter(models, getActivity());
recyclerView.setAdapter(adapter);
return view;
}
}
Adapter
public class MainRecylerAdapter extends RecyclerView.Adapter<MainRecylerAdapter.ViewHolder> {
List<Model> models = new ArrayList<>();
Context context;
private int index = 0;
public MainRecylerAdapter(List<Model> models, Context context) {
this.models = models;
this.context = context;
}
@NonNull
@Override
public MainRecylerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_recyler_layout, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final MainRecylerAdapter.ViewHolder holder, final int position) {
if (holder.isPlaying()) {
Log.e("TAG1", "play");
holder.releasePlayer();
holder.intiPlayer(models.get(position).getUrl());
} else {
Log.e("TAG1", "empty");
holder.intiPlayer(models.get(position).getUrl());
}
}
@Override
public int getItemCount() {
return models.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
SimpleExoPlayerView exoPlayerView;
SimpleExoPlayer exoPlayer;
private long playbackPosition;
private int currentWindow;
private boolean playWhenReady;
ProgressBar progressBar;
public ViewHolder(@NonNull View itemView) {
super(itemView);
exoPlayerView = itemView.findViewById(R.id.exoplayerview);
progressBar = itemView.findViewById(R.id.progress);
}
private void intiPlayer(String url) {
try {
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelector trackSelector = new DefaultTrackSelector(new AdaptiveTrackSelection.Factory(bandwidthMeter));
exoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
Uri videoURI = Uri.parse(url);
DefaultHttpDataSourceFactory dataSourceFactory = new DefaultHttpDataSourceFactory("exoplayer_video");
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
MediaSource mediaSource = new ExtractorMediaSource(videoURI, dataSourceFactory, extractorsFactory, null, null);
exoPlayerView.setPlayer(exoPlayer);
exoPlayer.prepare(mediaSource);
exoPlayer.setPlayWhenReady(true);
} catch (Exception e) {
Log.e("MainAcvtivity", " exoplayer error " + e.toString());
}
}
private boolean isPlaying() {
return exoPlayer != null
&& exoPlayer.getPlaybackState() != Player.STATE_ENDED
&& exoPlayer.getPlaybackState() != Player.STATE_IDLE
&& exoPlayer.getPlayWhenReady();
}
private void releasePlayer() {
if (exoPlayer != null) {
playbackPosition = exoPlayer.getCurrentPosition();
currentWindow = exoPlayer.getCurrentWindowIndex();
playWhenReady = exoPlayer.getPlayWhenReady();
exoPlayer.release();
exoPlayer = null;
}
}
}
here is a new concept to implement that so check this out Integrate RecyclerView with ExoPlayer — The clean way — and customization, my solution based on that article
P.S For cleaner code, we will be using Data binding Library and BindingAdapter so do not forget to enable these in gradle.
Lets create an extension function with @BindingAdapter annotation, that we will use to setup our PlayerView, with the values we have passed in our xml file as the arguments.
BindingData Adapter will be something like this
@BindingAdapter("video_url", "on_state_change")
fun PlayerView.loadVideo(url: String, callback: PlayerStateChange) {
if (url == null) return
val player = ExoPlayerFactory.newSimpleInstance(
context, DefaultRenderersFactory(context), DefaultTrackSelector(),
DefaultLoadControl()
)
player.playWhenReady = true
player.repeatMode = Player.REPEAT_MODE_ALL
// When changing track, retain the latest frame instead of showing a black screen
setKeepContentOnPlayerReset(true)
// We'll show the controller
this.useController = true
// Provide url to load the video from here
val mediaSource = ExtractorMediaSource.Factory(
DefaultHttpDataSourceFactory("Demo")
).createMediaSource(Uri.parse(url))
player.prepare(mediaSource)
this.player = player
this.player!!.addListener(object : Player.EventListener {
override fun onPlayerError(error: ExoPlaybackException?) {
super.onPlayerError(error)
[email protected]("Oops! Error occurred while playing media.")
}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
super.onPlayerStateChanged(playWhenReady, playbackState)
if (playbackState == Player.STATE_BUFFERING) callback.onVideoBuffering(player) // Buffering.. set progress bar visible here
if (playbackState == Player.STATE_READY){
// [PlayerView] has fetched the video duration so this is the block to hide the buffering progress bar
callback.onVideoDurationRetrieved([email protected], player)
}
if (playbackState == Player.STATE_READY && player.playWhenReady){
// [PlayerView] has started playing/resumed the video
callback.onStartedPlaying(player)
}
}
})
}
you can access a demo repo from here
via GIPHY
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With