如何在同一个RecyclerView中同时加载Firebase的图片与视频?
解决RecyclerView同时加载图片和视频(结合Toro+ExoPlayer)的问题
你现在的核心问题是没有区分RecyclerView的Item类型,所有条目都共用了一个实现了ToroPlayer的ViewHolder,这就导致图片条目也会被当成视频来处理,自然无法正常展示图片。下面咱们一步步调整代码来解决这个问题:
第一步:定义Item类型常量
首先在Adapter里明确两种条目类型,分别对应图片和视频:
private static final int TYPE_IMAGE = 0; private static final int TYPE_VIDEO = 1;
第二步:重写getItemViewType方法
根据Photo对象的属性判断当前条目类型,假设video_path不为空时是视频,否则是图片:
@Override public int getItemViewType(int position) { Photo photo = moviesList.get(position); return (photo.getVideo_path() != null && !photo.getVideo_path().isEmpty()) ? TYPE_VIDEO : TYPE_IMAGE; }
第三步:拆分ViewHolder
创建两个独立的ViewHolder,分别处理图片和视频逻辑(视频ViewHolder保留ToroPlayer的实现):
图片ViewHolder(仅处理图片展示和公共交互)
public class ImageViewHolder extends RecyclerView.ViewHolder { CircleImageView profile_image; TextView username, time, caption, likes, comment, stars; SquareImageView image; LikeButton mHeart, Star; ImageView commentBubble; public ImageViewHolder(View view) { super(view); profile_image = view.findViewById(R.id.post_profile_photo); username = view.findViewById(R.id.main_username); time = view.findViewById(R.id.main_image_time_posted); caption = view.findViewById(R.id.main_image_caption); likes = view.findViewById(R.id.main_likes); comment = view.findViewById(R.id.main_showcomments); image = view.findViewById(R.id.main_post_image); mHeart = view.findViewById(R.id.main_heart); Star = view.findViewById(R.id.main_star); stars = view.findViewById(R.id.stars); commentBubble = view.findViewById(R.id.main_comments); ButterKnife.bind(this, itemView); } }
视频ViewHolder(保留ToroPlayer播放逻辑)
public class VideoViewHolder extends RecyclerView.ViewHolder implements ToroPlayer { private ExoPlayerViewHelper helper; CircleImageView profile_image; TextView username, time, caption, likes, comment, stars; LikeButton mHeart, Star; ImageView commentBubble; private Uri mediaUri; @BindView(R.id.main_post_video) PlayerView playerView; public VideoViewHolder(View view) { super(view); profile_image = view.findViewById(R.id.post_profile_photo); username = view.findViewById(R.id.main_username); time = view.findViewById(R.id.main_image_time_posted); caption = view.findViewById(R.id.main_image_caption); likes = view.findViewById(R.id.main_likes); comment = view.findViewById(R.id.main_showcomments); mHeart = view.findViewById(R.id.main_heart); Star = view.findViewById(R.id.main_star); stars = view.findViewById(R.id.stars); commentBubble = view.findViewById(R.id.main_comments); ButterKnife.bind(this, itemView); } // ToroPlayer接口实现,保留你原有的逻辑 @NonNull @Override public View getPlayerView() { return playerView; } @NonNull @Override public PlaybackInfo getCurrentPlaybackInfo() { return helper != null ? helper.getLatestPlaybackInfo() : new PlaybackInfo(); } @Override public void initialize(@NonNull Container container, @Nullable PlaybackInfo playbackInfo) { if (helper == null) { helper = new SimpleExoPlayerViewHelper(container, this, mediaUri); } helper.initialize(playbackInfo); } void bind(Uri item) { if (item != null) { mediaUri = item; } } @Override public void play() { if (helper != null) helper.play(); } @Override public void pause() { if (helper != null) helper.pause(); } @Override public boolean isPlaying() { return helper != null && helper.isPlaying(); } @Override public void release() { if (helper != null) { helper.release(); helper = null; } } @Override public boolean wantsToPlay() { return ToroUtil.visibleAreaOffset(this, itemView.getParent()) >= 0.85; } @Override public int getPlayerOrder() { return getAdapterPosition(); } @Override public void onSettled(Container container) { } }
第四步:修改onCreateViewHolder
根据Item类型加载对应的布局(建议给图片和视频分别创建独立布局文件,比如main_list_image.xml和main_list_video.xml,避免视图复用冲突):
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mContext = parent.getContext(); if (viewType == TYPE_IMAGE) { View itemView = LayoutInflater.from(mContext) .inflate(R.layout.main_list_image, parent, false); return new ImageViewHolder(itemView); } else { View itemView = LayoutInflater.from(mContext) .inflate(R.layout.main_list_video, parent, false); return new VideoViewHolder(itemView); } }
第五步:修改onBindViewHolder
分别处理图片和视频的绑定逻辑,把公共逻辑(比如用户信息、点赞评论)抽成独立方法,避免代码重复:
@Override public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) { Photo photo = moviesList.get(position); // 公共逻辑:加载用户信息、点赞评论等 setupUserInfo(holder, photo); setupLikeAndStar(holder, photo); if (holder.getItemViewType() == TYPE_IMAGE) { ImageViewHolder imageHolder = (ImageViewHolder) holder; // 用图片加载库加载图片(示例用Glide) Glide.with(mContext) .load(photo.getImage_path()) .into(imageHolder.image); } else { VideoViewHolder videoHolder = (VideoViewHolder) holder; videoHolder.bind(Uri.parse(photo.getVideo_path())); } } // 公共方法:加载用户信息 private void setupUserInfo(RecyclerView.ViewHolder holder, Photo photo) { DatabaseReference reference = FirebaseDatabase.getInstance().getReference(); Query query = reference .child(mContext.getString(R.string.dbname_user_account_settings)) .orderByChild(mContext.getString(R.string.field_user_id)) .equalTo(photo.getUser_id()); query.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { for(DataSnapshot singleSnapshot : dataSnapshot.getChildren()){ UserAccountSettings settings = singleSnapshot.getValue(UserAccountSettings.class); if (holder instanceof ImageViewHolder) { ((ImageViewHolder)holder).username.setText(settings.getUsername()); Glide.with(mContext).load(settings.getProfile_photo()).into(((ImageViewHolder)holder).profile_image); } else if (holder instanceof VideoViewHolder) { ((VideoViewHolder)holder).username.setText(settings.getUsername()); Glide.with(mContext).load(settings.getProfile_photo()).into(((VideoViewHolder)holder).profile_image); } // 设置时间、标题等公共内容 ((TextView)holder.itemView.findViewById(R.id.main_image_time_posted)).setText(photo.getDate_created()); ((TextView)holder.itemView.findViewById(R.id.main_image_caption)).setText(photo.getCaption()); } } @Override public void onCancelled(DatabaseError databaseError) { Log.d(TAG, "onCancelled: 获取用户信息失败"); } }); } // 公共方法:处理点赞和收藏逻辑 private void setupLikeAndStar(RecyclerView.ViewHolder holder, Photo photo) { // 迁移你原有的getLikesString、getStarString等逻辑,根据holder类型设置对应视图 if (holder instanceof ImageViewHolder) { ImageViewHolder imageHolder = (ImageViewHolder) holder; getLikesString(imageHolder, photo); getStarString(imageHolder, photo); } else if (holder instanceof VideoViewHolder) { VideoViewHolder videoHolder = (VideoViewHolder) holder; getLikesString(videoHolder, photo); getStarString(videoHolder, photo); } }
第六步:适配Toro库容器
确保你的RecyclerView使用Toro提供的ToroRecyclerView,并在Activity/Fragment中初始化播放管理器:
// 在Activity中 private ToroPlayerHelper toroHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ToroRecyclerView recyclerView = findViewById(R.id.recycler_view); toroHelper = new ToroPlayerHelper(this, recyclerView); // 设置Adapter等逻辑 } @Override protected void onResume() { super.onResume(); toroHelper.onResume(); } @Override protected void onPause() { toroHelper.onPause(); super.onPause(); }
通过拆分Item类型和ViewHolder,让图片和视频各自使用独立的布局与逻辑,既能解决混合展示的问题,也能保证Toro库的视频自动播放功能正常工作。
内容的提问来源于stack exchange,提问作者user9822291
相关产品推荐
相关产品推荐

