Android Firebase Recyclerview 更改错误项目的值

标签 android firebase firebase-realtime-database android-recyclerview android-adapter

似乎发生的情况是,如果 Firebase 中的子项发生更改,recyclerview 会将最上面的项目替换为更改后的值。

enter image description here

例如,如果我将“微积分”更改为“化学”,它会将条目“生物学,约翰,晚上 7 点”替换为“化学,约翰,晚上 8 点”(当然仅在回收 View 本身中)。仅在使用 recreate() 重新启动 Activity 时才会更正 recyclerview。当 onChildRemoved 时,也会出现同样的问题,因为最上面的条目被删除(在回收器 View 中),而不是实际从数据库中删除的条目。

当我更改数据库引用以查看“请求”而不是“用户”时,此问题开始出现。

这是我用来更新列表的方法:

private void updateList() {

    reference.addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            result.add(dataSnapshot.getValue(RequestModel.class));
            adapter.notifyDataSetChanged();
        }

        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) {
            RequestModel model = dataSnapshot.getValue(RequestModel.class);

            int index = getItemIndex(model);

            result.set(index, model);
            adapter.notifyItemChanged(index);

        }

        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) {
            RequestModel model = dataSnapshot.getValue(RequestModel.class);

            int index = getItemIndex(model);

            result.remove(index);
            adapter.notifyItemRemoved(index);

        }

        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String s) {

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
}

这是索引方法:

private int getItemIndex(RequestModel request) {

    int index = -1;

    for (int i = 0; i < result.size(); i++) {
        if (result.get(i).key.equals(request.key)) {
            index = i;
            break;
        }

    }

    return index;
}

这是我的模型:

public class RequestModel {

String subject, time, name, key;

public RequestModel() {

}

public RequestModel(String subject, String time, String name, String key) {
    this.subject = subject;
    this.time = time;
    this.name = name;
    this.key = key;
 }
 }

编辑

onCreate方法:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    auth = FirebaseAuth.getInstance();

    String userID = auth.getCurrentUser().getUid();

    reference = FirebaseDatabase.getInstance().getReference().child("users").child(userID).child("requests");

    result = new ArrayList<>();

    recyclerView = (RecyclerView) findViewById(R.id.request_list);
    recyclerView.setHasFixedSize(true);
    LinearLayoutManager llm = new LinearLayoutManager(this);
    llm.setOrientation(LinearLayoutManager.VERTICAL);

    recyclerView.setLayoutManager(llm);

    adapter = new RequestAdapter(result);
    recyclerView.setAdapter(adapter);

    updateList();

更新列表指向@Chan Teck Wei 添加的方法。

这是所要求的适配器:

private List<RequestModel> list;

public RequestAdapter(List<RequestModel> list) {
    this.list = list;
}

@Override
public RequestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    return new RequestViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_items, parent, false));
}

@Override
public void onBindViewHolder(final RequestViewHolder holder, int position) {

    RequestModel request = list.get(position);

    holder.requestSubject.setText(request.subject);
    holder.requestTime.setText(request.time);
    holder.requestName.setText(request.name);

    holder.itemView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
        @Override
        public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
            contextMenu.add(holder.getAdapterPosition(), 0, 0, "Chat");
            contextMenu.add(holder.getAdapterPosition(), 1, 0, "Report");
        }
    });
}

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

class RequestViewHolder extends RecyclerView.ViewHolder {

    TextView requestSubject, requestTime, requestName;

    public RequestViewHolder(View itemView) {
        super(itemView);

        requestSubject = (TextView) itemView.findViewById(R.id.request_subject);
        requestTime = (TextView) itemView.findViewById(R.id.request_time);
        requestName = (TextView) itemView.findViewById(R.id.request_name);
    }
}

最佳答案

假设您的引用指向users/key/requests。首先,您将稍微修改一下 RequestModel 类。

public class RequestModel {

String subject, time, name, key;
private String mKey;

public RequestModel() {

}

public RequestModel(String subject, String time, String name, String key) {
    this.subject = subject;
    this.time = time;
    this.name = name;
    this.key = key;
}

public void setKey(String key) {
    mKey = key;
}

public String getKey() {
    return mKey;
}
}

setKey() 用于使用从数据库获取的唯一键设置 RequestModel 对象。然后,getKey() 将用于识别对象的实际 key 。这对于编辑操作很有用。

ChildEventListener listener = new ChildEventListener() {
     @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            RequestModel request = dataSnapshot.getValue(RequestModel.class);
            request.setKey(dataSnapshot.getKey());
            result.add(request);
            adapter.notifyItemInserted(result.size());
        }

        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) {
            RequestModel request = dataSnapshot.getValue(RequestModel.class);
            request.setKey(dataSnapshot.getKey());
            for (int i = 0; i < result.size(); i++) {
                if (result.get(i).getKey().equals(request.getKey())) {
                    result.set(i, request);
                    adapter.notifyItemChanged(i);
                    break;
                }
            }
        }

        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) {
            RequestModel request = dataSnapshot.getValue(RequestModel.class);
            request.setKey(dataSnapshot.getKey());
            for (int i = 0; i < result.size(); i++) {
                if (result.get(i).getKey().equals(request.getKey())) {
                    result.remove(i);
                    adapter.notifyItemRemoved(i);
                    break;
                }
            }

        }

        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String s) {

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

就个人而言,此实现比在方法 onChildAdded() 中使用 notifyDataSetChanged() 更好。而且,动画很养眼。

关于Android Firebase Recyclerview 更改错误项目的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48876703/

相关文章:

android - 在 Android 中操作自定义 GLSurfaceView

java - 应用程序在切换 Activity 时退出沉浸模式

java - 使用 GeoFirestore 的 Firestore 中的数据结构

java - 如何迭代 Firebase 数据库中的节点?

java - 在应用程序上使用时,对每个 "getKey()"的 Firebase 上的所有数据进行重新分组

android - Fragments如何影响Activity "single, focused thing that the user can do"原理?

android - 在 AchartEngine 中禁用平移后的性能问题

firebase - 用户名认证而不是电子邮件

android - Exoplayer : Loop creates OutOfMemoryError when playing video from local file

node.js - 实时数据库功能不断触发