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

RecyclerView状态变更Item移除实现失败,寻求解决方案

问题:RecyclerView Item状态变更时无法自动移除

我需要实现的功能是:当RecyclerView中Item对应的行程状态在数据库中变更为-1(代表行程取消或结束)时,自动将该Item从列表中移除。

尝试过程:

  • 先在主Activity中实现该逻辑,未成功
  • 后在Adapter的onBindViewHolder方法中监听数据库变更,但onDataChange始终无法触发

当前正常流程:新行程请求到来时,通过以下代码可成功将行程添加到RecyclerView:

resultsTestList.add(mCurrentRide);
mTestListAdapter.notifyDataSetChanged();

需求:当另一个Activity将数据库中行程状态设为-1(满足mRide.getCancelled() || mRide.getEnded() == true)时,对应Item自动从RecyclerView列表中移除。


相关代码

Adapter类代码

@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onBindViewHolder(@NotNull TestListeAdapter.TestListeViewHolders holder, @SuppressLint("RecyclerView") final int position) {
    holder.bindView(position);
    RideObject item = itemList.get(position);

    Query query = FirebaseDatabase.getInstance("https://west1.firebasedatabase.app")
            .getReference().child("ride_info").child(item.getId());

    query.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            if (!snapshot.exists()) {
                return;
            }

            RideObject mRide = new RideObject();
            mRide.parseData(snapshot);

            if (mRide.getCancelled() || mRide.getEnded()) {
                itemList.remove(position);
                notifyItemRemoved(position);
            }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
        }
    });
}

Activity类核心代码

private void getRequestInfo(String key) {
    FirebaseDatabase.getInstance("https://west1.firebasedatabase.app")
            .getReference().child("ride_info").child(key)
            .addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(@NotNull DataSnapshot dataSnapshot) {
                    if (!dataSnapshot.exists()) {
                        return;
                    }

                    if (mCurrentRide != null) {
                        return;
                    }

                    RideObject mRide = new RideObject();
                    mRide.parseData(dataSnapshot);
                    if(mRide.getCancelled()){
                        return;
                    }

                    try {
                        mCurrentRide = (RideObject) mRide.clone();
                        getAssignedCustomerInfo();
                    } catch (CloneNotSupportedException e) {
                        e.printStackTrace();
                    }
                    
                    mEmpty.setVisibility(View.GONE);
                }

                @Override
                public void onCancelled(@NotNull DatabaseError databaseError) {
                }
            });
}

public void getAssignedCustomerInfo() {
    String driverId = FirebaseAuth.getInstance().getCurrentUser().getUid();
    if (mCurrentRide.getCustomer().getId() == null) {
        return;
    }
    DatabaseReference mCustomerDatabase = FirebaseDatabase.getInstance("https://west1.firebasedatabase.app")
            .getReference().child("Users").child("Patient").child(mCurrentRide.getCustomer().getId());
    mCustomerDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NotNull DataSnapshot dataSnapshot) {
            if (!dataSnapshot.exists()) {
                return;
            }
            if (mCurrentRide!= null) {
                mCurrentRide.getCustomer().parseData(dataSnapshot);
            }
        }

        @Override
        public void onCancelled(@NotNull DatabaseError databaseError) {
        }
    });
    FirebaseDatabase.getInstance("https://west1.firebasedatabase.app")
            .getReference("praticienWorking").child(driverId)
            .addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {
                    DatabaseReference ref = FirebaseDatabase.getInstance("https://west1.firebasedatabase.app")
                            .getReference().child("ride_info").child(mCurrentRide.getId());
                    if (!mCurrentRide.getCancelled() && !mCurrentRide.getEnded() 
                        && mCurrentRide.getDriver() == null && mCurrentRide.getState() == 0) {
                        resultsTestList.add(mCurrentRide);
                        mTestListAdapter.notifyDataSetChanged();
                        makeSound();
                    }
                }

                @Override
                public void onCancelled(@NonNull DatabaseError error) {
                }
            });
}

问题原因与修复方案

问题原因

  1. 使用单次监听而非实时监听:Adapter中调用addListenerForSingleValueEvent只会获取一次数据,后续数据库状态变更不会触发onDataChange。
  2. Adapter中监听逻辑不合理:RecyclerView的Item会复用,每次绑定都添加监听会导致逻辑混乱和内存泄漏,且无法持续监听状态变化。
  3. 数据同步逻辑分散:Activity和Adapter各维护数据,没有统一的实时状态监听机制,导致数据不一致。

修复方案

1. 在Activity中统一管理实时监听

将行程的状态监听逻辑移到Activity中,使用addValueEventListener实现实时监听,状态变更时直接更新列表并通知Adapter:

// 存储行程与对应监听的映射,用于后续清理
private Map<RideObject, ValueEventListener> mRideListeners = new HashMap<>();

// 添加行程时同时绑定实时监听
private void addRideWithRealtimeListener(RideObject ride) {
    DatabaseReference rideRef = FirebaseDatabase.getInstance("https://west1.firebasedatabase.app")
            .getReference().child("ride_info").child(ride.getId());
    
    ValueEventListener rideListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            if (!snapshot.exists()) {
                removeRide(ride);
                rideRef.removeEventListener(this);
                return;
            }
            
            RideObject updatedRide = new RideObject();
            updatedRide.parseData(snapshot);
            
            if (updatedRide.getCancelled() || updatedRide.getEnded()) {
                removeRide(ride);
                rideRef.removeEventListener(this);
            }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
            rideRef.removeEventListener(this);
        }
    };
    
    rideRef.addValueEventListener(rideListener);
    mRideListeners.put(ride, rideListener);
    
    resultsTestList.add(ride);
    mTestListAdapter.notifyItemInserted(resultsTestList.size() - 1);
}

// 移除行程的统一方法
private void removeRide(RideObject ride) {
    int position = resultsTestList.indexOf(ride);
    if (position != -1) {
        resultsTestList.remove(position);
        mTestListAdapter.notifyItemRemoved(position);
    }
}

2. 简化Adapter逻辑

Adapter只负责数据绑定,不再处理数据库监听:

@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onBindViewHolder(@NotNull TestListeViewHolders holder, int position) {
    RideObject item = itemList.get(position);
    holder.bindView(item); // 仅做UI数据绑定
}

3. 清理监听避免内存泄漏

在Activity销毁时移除所有行程的监听:

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mRideListeners != null) {
        for (Map.Entry<RideObject, ValueEventListener> entry : mRideListeners.entrySet()) {
            FirebaseDatabase.getInstance("https://west1.firebasedatabase.app")
                    .getReference().child("ride_info").child(entry.getKey().getId())
                    .removeEventListener(entry.getValue());
        }
        mRideListeners.clear();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 11:40:29