Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exoplayer with Recyclerview

Tags:

java

android

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;
            }
        }


    }
like image 754
Mukesh Kumar Avatar asked Jan 01 '23 03:01

Mukesh Kumar


1 Answers

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

like image 84
Mostafa Anter Avatar answered Jan 02 '23 17:01

Mostafa Anter