从餐厅页返回主页面时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
相关产品推荐
相关产品推荐

