java - 带有 Recyclerview 的 Exoplayer

标签 java android

我有一个视频源(类似于 TikTok),但是当我向上滑动新视频时,旧视频仍在播放。我设法获得了一个页面监听器,但我无法从“家庭 fragment ”控制 ExoPlayer。
关于如何从 Home Fragment 触发 RecyclerView 适配器内部的东西的任何想法?
如果有更好的解决方案,请告诉我。
首页 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;
    }
}
适配器
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;
            }
        }


    }

最佳答案

这是一个要实现的新概念,因此请查看将 RecyclerView 与 ExoPlayer 集成 — 干净的方式 — 和自定义,我的解决方案基于该 article
P.S 对于更简洁的代码,我们将使用数据绑定(bind)库和 BindingAdapter,所以不要忘记在 gradle 中启用它们。
让我们创建一个带有 @BindingAdapter 注释的扩展函数,我们将使用它来设置我们的 PlayerView,并将我们在 xml 文件中传递的值作为参数。
BindingData 适配器将是这样的

@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)
        this@loadVideo.context.toast("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(this@loadVideo.player.duration, player)
        }
        if (playbackState == Player.STATE_READY && player.playWhenReady){
            // [PlayerView] has started playing/resumed the video
            callback.onStartedPlaying(player)
        }
    }
})
}
您可以从 here 访问演示 repo
via GIPHY

关于java - 带有 Recyclerview 的 Exoplayer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61455134/

相关文章:

android - 文件未添加到图库 android

android - 我如何从图库中选择图像?

Java MySQL 防止竞争条件

java - webview离线时隐藏或替换 "webpage not available"

Java 调用并等待?

android - 错误 :(26, 13) 无法解析 : com. android.support :appcompat-v7:27. +

java - DWR 3.0.rc2 和 Maven

java - 为什么不调用notify wait就释放锁

android - dart 状态小部件将数据传递到状态错误 : widget is null

Android NestedScrollView fillViewport 拉伸(stretch)不正确