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

从餐厅页返回主页面时Firestore RecyclerView出现位置越界错误

RecyclerView返回主页面出现IndexOutOfBoundsException的解决方案

这个错误的核心原因是RecyclerView视图持有者(ViewHolder)的位置与适配器数据集不一致,通常发生在实时数据源(如Firestore)后台更新后,或视图复用过程中位置失效,再加上通过position获取数据的方式本身存在风险——一旦数据集变化,原position对应的可能已不是之前的对象。

以下是针对性的解决步骤:

1. 直接传递绑定的数据对象,摒弃position依赖

修改适配器的点击回调逻辑,直接传递当前绑定的Restaurant对象,彻底避免位置偏移问题:

修改Adapter代码

private OnItemClickListener mListener;

// 调整接口,直接传递Restaurant对象
public interface OnItemClickListener {
    void onItemClick(Restaurant restaurant);
}

public void setOnItemClickListener(OnItemClickListener listener) {
    mListener = listener;
}

@Override
protected void onBindViewHolder(@NonNull resviewHolder holder, int position, @NonNull Restaurant model) {
    holder.name.setText(model.getName());
    holder.phone.setText(model.getPhone());
    holder.address.setText(model.getAddress());
    holder.category.setText(model.getCategory());
    holder.averageRating.setRating(model.getAverageRating());

    // 加载图片
    Glide.with(holder.itemView.getContext())
            .load(model.getPhotoUrl())
            .into(holder.imageView);

    // 点击事件直接传递当前绑定的model
    holder.itemView.setOnClickListener(v -> {
        if (mListener != null) {
            mListener.onItemClick(model);
        }
    });
}

@Override
public int getItemCount() {
    return super.getItemCount();
}

修改MainActivity的回调逻辑

adapter.setOnItemClickListener(restaurant -> {
    // 直接使用传递过来的restaurant对象
    Intent intent = new Intent(MainActivity.this, ViewRestaurantActivity.class);
    intent.putExtra("restaurant_name", restaurant.getName());
    intent.putExtra("restaurant_phone", restaurant.getPhone());
    intent.putExtra("restaurant_address", restaurant.getAddress());
    intent.putExtra("restaurant_category", restaurant.getCategory());
    intent.putExtra("restaurant_photoUrl", restaurant.getPhotoUrl());
    intent.putExtra("restaurant_cordX", restaurant.getCordX());
    intent.putExtra("restaurant_cordY", restaurant.getCordY());
    intent.putExtra("rating_avg", restaurant.getAverageRating());
    startActivity(intent);
});

2. 正确管理Firestore监听的生命周期

确保在Activity可见时才监听数据变化,不可见时停止监听,避免后台数据更新导致数据集与视图状态不匹配:

private ListenerRegistration firestoreListener;

@Override
protected void onStart() {
    super.onStart();
    // 注册Firestore实时监听
    firestoreListener = db.collection("restaurants")
            .addSnapshotListener((snapshots, e) -> {
                if (e != null) {
                    Log.w(TAG, "监听失败", e);
                    return;
                }
                // 更新适配器数据集
                List<Restaurant> restaurants = new ArrayList<>();
                for (QueryDocumentSnapshot doc : snapshots) {
                    Restaurant restaurant = doc.toObject(Restaurant.class);
                    restaurants.add(restaurant);
                }
                adapter.submitList(restaurants);
            });
}

@Override
protected void onStop() {
    super.onStop();
    // 移除监听,避免内存泄漏和后台更新
    if (firestoreListener != null) {
        firestoreListener.remove();
    }
}

如果使用的是FirestoreRecyclerAdapter,则替换为以下生命周期管理:

@Override
protected void onStart() {
    super.onStart();
    adapter.startListening();
}

@Override
protected void onStop() {
    super.onStop();
    adapter.stopListening();
}

内容的提问来源于stack exchange,提问作者user24480020

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 12:23:11