You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在同一个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:08:34