【问题标题】:Android Java - RecyclerView with Firestore not Updating on Item RemovalAndroid Java - 带有 Firestore 的 RecyclerView 不更新项目删除
【发布时间】:2020-01-09 00:02:37
【问题描述】:

我正在使用 Firestore 来保存代表有名字的人的文档。我正在使用 RecyclerView 来显示它们,并使用显示从 Firestore 中提取的名称的卡片填充它。我实现了滑动删除功能,当您在 RecyclerView 中向左或向右滑动此人的卡片时,该功能会从 Firestore 中删除此人。

我的问题是刷卡不会导致 RecyclerView 更新 - 当我检查 Firestore 时,确实发生了删除,但 RecyclerView 只是显示了该卡过去所在的位置。已移除卡片下方的卡片均不会“向上移动”以填补空白。

在包含 RecyclerView 的活动的 onCreate() 内部,我调用了一个名为 setUpRecyclerView() 的函数。这是那个函数,其中包含刷卡的代码:

private void setUpRecyclerView() {
    // create the query who's results you want to populate the recyclerView with
    Query query = clientsReference.orderBy("lastNameLowercase")
            .orderBy("firstNameLowercase");

    // how we get the query into the adapter
    FirestoreRecyclerOptions<Client> options = new FirestoreRecyclerOptions.Builder<Client>()
            .setQuery(query, Client.class)
            .build();

    // assign the adapter
    adapter = new ClientAdapter(options);

    RecyclerView recyclerView = findViewById(R.id.recycler_view);
    recyclerView.setHasFixedSize(true);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setAdapter(adapter);

    /**
     * This section handles what happens when you swipe an item in the recyclerView list
     */
    new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,
            ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
            return false;
        }

        @Override
        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
            int position = viewHolder.getAdapterPosition();
            adapter.deleteClient(position);
            //adapter.notifyItemRemoved(position);
        }
    }).attachToRecyclerView(recyclerView);

    /**
     * This section handles what happens when you click on an item in the recyclerView list
     */
    adapter.setOnItemClickListener(new ClientAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(DocumentSnapshot documentSnapshot, int position) {
            Client client = documentSnapshot.toObject(Client.class);
            String id = documentSnapshot.getId();
            Intent intentDisplayClient = new Intent(MainActivity.this, DisplayClientActivity.class);

            // Pass ahead the client's id from Firestore to the next activity
            intentDisplayClient.putExtra(KEY_ID, id);
            startActivity(intentDisplayClient);
        }
    });
}

这是适配器类:

public class ClientAdapter extends FirestoreRecyclerAdapter<Client, ClientAdapter.ClientHolder> {

private OnItemClickListener listener;

/**
 * Create a new RecyclerView adapter that listens to a Firestore Query.
 */
public ClientAdapter(@NonNull FirestoreRecyclerOptions<Client> options) {
    super(options);
}

@Override
protected void onBindViewHolder(@NonNull ClientHolder holder, int position, @NonNull Client model) {
    String lastNameWithComma = model.getLastName() + ", ";
    holder.textViewLastName.setText(lastNameWithComma);
    holder.textViewFirstName.setText(model.getFirstName());
}

@NonNull
@Override
public ClientHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.client_list_item, parent, false);
    return new ClientHolder(v);
}

public void deleteClient(int position) {
    getSnapshots().getSnapshot(position).getReference().delete();
}

class ClientHolder extends RecyclerView.ViewHolder {
    TextView textViewLastName;
    TextView textViewFirstName;

    public ClientHolder(@NonNull View itemView) {
        super(itemView);
        textViewLastName = itemView.findViewById(R.id.rv_tv_last_name);
        textViewFirstName = itemView.findViewById(R.id.rv_tv_first_name);

        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = getAdapterPosition();
                if (position != RecyclerView.NO_POSITION && listener != null) {
                    listener.onItemClick(getSnapshots().getSnapshot(position), position);
                }
            }
        });
    }
}

public interface OnItemClickListener {
    void onItemClick(DocumentSnapshot documentSnapshot, int position);
}

public void setOnItemClickListener(OnItemClickListener listener) {
    this.listener = listener;
}
}

您会注意到 setUpRecyclerView() 内部的 onSwiped() 函数中有一行注释掉了。当使用该行时,会发生其他不希望的行为:RecyclerView 确实“向上移动”较低的卡片以填补被移除卡片留下的空白,但是 RecyclerView 底部的任何一张卡片都会被复制并放置在底部。所以如果它看起来像这样:

一个 乙 C D

...然后我扫掉C,然后它看起来像这样:

一个 乙 D D

所以我被困在列表根本没有更新,或者以一种没有意义的奇怪方式更新。

如果您有兴趣,我会按照本教程进行操作,但它不起作用:

https://www.youtube.com/watch?v=dTuhMFP-a1g&list=PLrnPJCHvNZuAXdWxOzsN5rgG2M4uJ8bH1&index=6&t=0s

【问题讨论】:

  • 请参考this。我用这个解决了我的问题。希望它有所帮助。
  • @harshsuvagiya 我检查了该线程和我通过它找到的其他一些线程,但没有一个建议的解决方案可以解决我的问题。你能具体告诉我你做了什么来修复你的吗?

标签: android android-recyclerview google-cloud-firestore


【解决方案1】:

如果您使用FirestoreRecyclerAdapter,则无需手动通知您的适配器。数据库中的更改将反映在您的 UI 中。因此,无需致电adapter.notifyItemRemoved(position)

另外,delete(...) 是异步执行的。所以需要添加回调来查看文档是否删除成功:

public void deleteClient(int position) {
    getSnapshots().getSnapshot(position).getReference().delete()
         .addOnSuccessListener(new OnSuccessListener<Void>() {
              @Override
              public void onSuccess(Void aVoid) {
                  Log.d(TAG, "DocumentSnapshot successfully deleted!");
              }
    })
    .addOnFailureListener(new OnFailureListener() {
         @Override
         public void onFailure(@NonNull Exception e) {
              Log.w(TAG, "Error deleting document", e);
         }
    });
}

【讨论】:

  • 我添加了您提供的代码,上面写着“TAG 在 FirestorerecyclerAdapter 中有私有访问权限”。当我删除 Log 行(并且只实现其他所有内容,以便在 onSuccess 或 onFailure 期间没有任何反应)时,它编译并运行良好,但我的问题仍然存在。
【解决方案2】:

请参考this。我用这个解决了我的问题。希望它有所帮助。

你必须把它写在 onStart() 方法中。 你也这样做了吗?

【讨论】:

  • 我在上面看到了您的评论并做出了回应。你是说我需要将快照监听器添加到 onStart()?
  • 抱歉回复晚了!只需将所有数据作为 db.collection().document().addSnapshotListner(new EventValueListner)... 而不是 db.collection().document().get().OnComplete....
  • 对不起,我很困惑!你说“而不是...... OnComplete......”但我不知道你在我的代码中看到 OnComplete 的什么地方。我在 onStart() 中没有任何代码。在您最初的帖子中,您链接了一些代码,但我不知道该放在哪里。在 onStart() 中,我已经调用了 adapter.startListening(),但这就是我在那里所做的一切。如果可能的话,您能否按照您认为我需要做的事情来编辑您的帖子?
  • 我还没有尝试过 FirestoreRecyclerAdapter。我在谈论以更简单的方式获取数据,即制作我们自己的适配器并将列表发送到该适配器的构造函数中。因此,您必须根据上述评论获取数据并将该列表发送给构造函数。如果再次让您感到困惑,我很抱歉!
【解决方案3】:

在查询查询中删除 .orderby 这对我有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多