向聊天室添加消息后,FirestoreRecyclerAdapter Recyclerview UI 没有改变

FirestoreRecyclerAdapter Recyclerview UI doesn't change after adding a message to the chatroom

当我在聊天室中单击发送按钮时,我可以将消息添加到 firestore,但 recyclerview 不会实时更新,因此不会显示新消息。当我重新打开聊天室时确实会出现该消息,这不是最佳做法。通常 FirestoreRecyclerAdapter 应该在进行更改时自动更新查询并更新 recyclerview。 我在 Android Studio 中使用 Java 并使用片段而不是活动。

聊天室片段:

public class ChatRoomFragment extends Fragment {
    private static final String TAG = "Notable:ChatRoom";
    private FirebaseFirestore db;
    private Query query;
    private FirestoreRecyclerAdapter<Message, MessageAdapter.MessageHolder> adapter;
    private FirebaseAuth mAuth;
    private FirebaseUser currentUser;

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.chatroom_fragment, container, false);
        MaterialToolbar topBar = view.findViewById(R.id.topAppBar);
        Button sendButton = view.findViewById(R.id.send_message);
        EditText input = view.findViewById(R.id.message_edit_text);
        RecyclerView chatRecyclerView = view.findViewById(R.id.chat_recyclerview);
        mAuth = FirebaseAuth.getInstance();
        currentUser = mAuth.getCurrentUser();
        db = FirebaseFirestore.getInstance();
        //FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder().setPersistenceEnabled(true).setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED).build();
        //db.setFirestoreSettings(settings);
        String key = mAuth.getCurrentUser().getUid();
        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
        layoutManager.setStackFromEnd(true);
        chatRecyclerView.setLayoutManager(layoutManager);

        String title = this.getArguments().getString("buttonText");
        topBar.setTitle(title);

        query = db.collection("messages").whereEqualTo("chatGroup", title).orderBy("messageTime");
        adapter = new MessageAdapter(getActivity(), query, key);
        //https://medium.com/@akhilkc9/simple-android-chat-application-using-firestorerecycleradapter-7f632da2eaee
        adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
            @Override
            public void onItemRangeChanged(int positionStart, int itemCount) {
                super.onItemRangeChanged(positionStart, itemCount);
                chatRecyclerView.scrollToPosition(itemCount);
            }
        });
        chatRecyclerView.setAdapter(adapter);

        sendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String text = input.getText().toString();
                if(!text.equals("")){
                    db.collection("users").document(key).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
                        @Override
                        public void onSuccess(DocumentSnapshot documentSnapshot) {
                            if (documentSnapshot.exists()){
                                String firstName = documentSnapshot.get("firstname").toString();
                                db.collection("messages").add(new Message(firstName, text, key, title));
                            }else{
                                Log.w(TAG, "No such document");
                            }
                        }
                    });
                }
                input.setText("");
            }
        });

        return view;
    }

    @Override
    public void onStart() {
        super.onStart();
        if(adapter!=null) adapter.startListening();
    }

    @Override
    public void onStop() {
        super.onStop();
        if(adapter!=null) adapter.stopListening();
    }
}

消息适配器:

public class MessageAdapter extends FirestoreRecyclerAdapter<Message, MessageAdapter.MessageHolder> {
    private final String TAG = "MessageAdapter";
    Context context;
    String userId;
    StorageReference storageReference;
    private RequestOptions requestOptions = new RequestOptions();
    private final int MESSAGE_IN_VIEW_TYPE  = 1;
    private final int MESSAGE_OUT_VIEW_TYPE = 2;

    public MessageAdapter(@NonNull Context context, Query query, String userID) {
        super(new FirestoreRecyclerOptions.Builder<Message>().setQuery(query, Message.class).build());
        this.context = context;
        this.userId = userID;
    }

    @Override
    public int getItemViewType(int position) {
        if(getItem(position).getMessageUserId().equals(userId)){
            return MESSAGE_IN_VIEW_TYPE;
        }
        return MESSAGE_OUT_VIEW_TYPE;
    }

    @Override
    public MessageHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = null;
        if(viewType==MESSAGE_IN_VIEW_TYPE){
            view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.chat_item, parent, false);
        }else{
            view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.chat_item_other, parent, false);
        }
        return new MessageHolder(view);
    }

    //Voordeel van Recyclerview is dat het automatisch een Viewholder heeft, dit heeft gridview niet automatisch
    @Override
    protected void onBindViewHolder(@NonNull MessageHolder holder, int position, @NonNull Message model) {
        final TextView mText = holder.mText;
        final TextView mUsername = holder.mUsername;
        final TextView mTime = holder.mTime;
        final TextView mDate = holder.mDate;
        final ImageView imgProfile = holder.imgProfile;

        if(mUsername != null && imgProfile != null){
            mUsername.setText(model.getMessageUser());
            //Glide.with(context).setDefaultRequestOptions(requestOptions).load(R.drawable.placeholder).diskCacheStrategy(DiskCacheStrategy.DATA).into(imgProfile);
            //storageReference.child(model.getMessageUserId())
        }
        mText.setText(model.getMessageText());
        mDate.setText(DateFormat.format("dd MMM", model.getMessageTime()));
        mTime.setText(DateFormat.format("h:mm", model.getMessageTime()));

    }

    static class MessageHolder extends RecyclerView.ViewHolder {

        TextView mText;
        TextView mUsername;
        TextView mTime;
        TextView mDate;
        ImageView imgProfile;

        public MessageHolder(View itemView) {
            super(itemView);
            mText = itemView.findViewById(R.id.message_text);
            mUsername = itemView.findViewById(R.id.message_user);
            mTime = itemView.findViewById(R.id.message_time);
            mDate = itemView.findViewById(R.id.message_date);
            imgProfile = itemView.findViewById(R.id.imgDps);
        }
    }
}

chatroom_fragment.xml :

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/layout_group_chat"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:orientation="vertical"
        app:layout_constraintTop_toTopOf="parent">

        <com.google.android.material.appbar.MaterialToolbar
            android:id="@+id/topAppBar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:title="@string/chat_group"
            style="@style/Widget.MaterialComponents.Toolbar.Primary" />
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/chat_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="16dp"
        app:layout_constrainedHeight="true"
        app:layout_constraintBottom_toTopOf="@+id/text_indicator"
        app:layout_constraintTop_toBottomOf="@+id/layout_group_chat" />

    <TextView
        android:id="@+id/text_indicator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:visibility="gone"
        app:layout_constraintBottom_toTopOf="@id/view"
        app:layout_constraintStart_toStartOf="parent" />

    <View
        android:id="@+id/view"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#e0e0e0"
        app:layout_constraintBottom_toTopOf="@+id/layout_chatbox" />

    <RelativeLayout
        android:id="@+id/layout_chatbox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent">


        <EditText
            android:layout_marginStart="16dp"
            android:id="@+id/message_edit_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:background="@android:color/transparent"
            android:hint="@string/hint_message"
            android:inputType="text"
            android:maxLines="6"
            tools:ignore="Autofill" />

        <Button
            android:id="@+id/send_message"
            android:layout_width="74dp"
            android:layout_height="48dp"
            android:layout_alignParentEnd="true"
            android:background="?attr/selectableItemBackground"
            android:text="@string/send"
            android:textColor="@color/design_default_color_primary" />

    </RelativeLayout>


</androidx.constraintlayout.widget.ConstraintLayout>

问题解决了,是因为我没有为firestore上的查询添加索引。 我从 android studio console(和 firestore)中得到一个错误,解释它见 link:

https://coderedirect.com/questions/651254/firebase-firestore-query-error-9-failed-precondition-the-query-requires-an-i