Home > Back-end >  RecyclerView not loading data correctly from FirebaseFirestore
RecyclerView not loading data correctly from FirebaseFirestore

Time:05-31

I'm creating an app on Android Studio with Java and Firestore that lets users make publications and show them on a Fragment with a RecyclerView. The users create a profile (name, avatar) that gets saved in a document named after the user UID inside a collection named "Users". The publications are saved into another collection named "Posts" (title, content, picture, avatar, name).

I wrote two queries, one to get the title and content from the posts from the "Posts" collection, as well as the UID, to then do the other query that gets the name and picture from the poster and then all of those fields go inside a "Post" object and sent to the ArrayList that fills the RecyclerView.

Problem: The posts load perfectly on the RecyclerView but the user picture (the one I'm getting from a different collection) is giving me lots of problems. Sometimes it loads, sometimes it doesn't, and sometimes it loads only for the first post or even the first three posts. I don't understand what could be wrong. I'm posting the code:

private void loadPosts() {
        Query postQuery = collectionReferencePosts.orderBy("timestamp", Query.Direction.DESCENDING);
        postQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                for (QueryDocumentSnapshot document : task.getResult()) {
                    Post post = new Post();
                    post.setTitle(document.getString("title"));
                    post.setContent(document.getString("content"));
                    post.setImage(document.getString("image"));
                    String posterUid = document.getString("useruid");
                    DocumentReference docRef = collectionReferenceUsers.document(posterUid);
                    docRef.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
                        @Override
                        public void onSuccess(DocumentSnapshot documentSnapshot) {
                            post.setName(documentSnapshot.getString("name").toString());
                            post.setAvatar(documentSnapshot.getString("image").toString());
                        }
                    });
                    postList.add(post);
                    postAdapter.notifyDataSetChanged();
                }
            }
        });
    }

CodePudding user response:

If you want to display post details, along with user details at the same time, then you have to notify the adapter about the changes when the second request for getting the name and the image is complete. So you have to move the following two lines of code:

postList.add(post);
postAdapter.notifyDataSetChanged();

Right after:

post.setAvatar(documentSnapshot.getString("image").toString());

Besides that, there is another option that you should consider using, which is called denomalization. This means that you can add the name and the image of the user inside the post document. In this way, there is no need to perform the second query, since all the data already exists inside the post document. If you're new to NoSQL databases, this might sound some kind of weird, but I assure you it's quite common practice.

Please also note, that neither solution is better than the other. According to the number of changes that can occur in your app, regarding the update of name and user image, you have to check which solution is better to be used inside your project.

You can also take a look at the following post to have a better understanding of the asynchronous nature of Firebase API:

  • Related