英文:
How to pause ExoPlayer playerView when RecyclerView.SCROLL_STATE_DRAGGING and release player on Destroy
问题
我想实现一个类似Instagram动态的RecyclerView,其中包含图像和视频项目。我已经成功地实现了RecyclerView来显示图像和视频项目,但是当onScrollListener处于RecyclerView.SCROLL_STATE_DRAGGING
状态时,我在暂停视频项目方面遇到了问题。我正在使用ExoPlayer库用于视频播放器。
因此,如果播放一个视频并且RecyclerView没有暂停,即使从列表中播放另一个视频,它仍然会继续播放该视频。导致多个视频同时播放。
下面是我实现的适配器:
public class RecyclerAdapter extends RecyclerView.Adapter {
// ... (省略适配器的其余部分)
@Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
ListModel listModel = listModelList.get(position);
if (listModel.getDescription().equalsIgnoreCase("video")) {
final VideoVH videoVH = (VideoVH) holder;
initPlayer(videoVH.playerView, listModel.getMedia_url(), videoVH.progressBar);
videoVH.titleText.setText(listModel.getTitle());
videoVH.descText.setText(listModel.getDescription());
// 在这里添加逻辑来暂停视频播放器
if (shouldPauseVideoDuringScrolling) {
videoVH.playerView.getPlayer().setPlayWhenReady(false);
} else {
videoVH.playerView.getPlayer().setPlayWhenReady(true);
}
} else {
// ... (省略图像项目的处理)
}
}
// ... (省略适配器的其余部分)
}
在你的 RecyclerAdapter
类中,根据 RecyclerView
的滚动状态来控制视频播放。你需要在 onBindViewHolder
方法中检查 shouldPauseVideoDuringScrolling
的状态,根据这个状态来决定是否暂停视频播放器。具体的逻辑可以根据你的需求来进行调整。
另外,在你的 MainActivity
中,你需要添加一个 RecyclerView.OnScrollListener
来监听滚动状态并相应地更新 shouldPauseVideoDuringScrolling
的值。可以在 initRecyclerView
方法中添加以下代码:
private void initRecyclerView() {
// ... (其余初始化代码)
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// 判断是否处于拖动状态
shouldPauseVideoDuringScrolling = newState == RecyclerView.SCROLL_STATE_DRAGGING;
// 更新适配器以根据滚动状态更新视频播放器的播放状态
mAdapter.notifyDataSetChanged();
}
});
// ... (其余初始化代码)
}
这样,当RecyclerView处于滚动拖动状态时,视频播放器会被暂停,从而实现你所需的功能。同时,根据滚动状态的变化,适配器会及时更新视频播放器的播放状态。
至于在RecyclerView中实现类似Instagram动态的布局,你已经在适配器中实现了不同类型的视图(图像和视频),因此基本上你已经在正确的方向上。你可以根据需要继续添加其他功能,比如显示用户信息、点赞和评论等。
英文:
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
专注分享java语言的经验与见解,让所有开发者获益!
评论