0

When I run this activity, it records the visible list objects to an array, but when I scroll down and go back up, it duplicates the elements again into the array. How to fix it? For an item to be added only once.

I have tried set but getting the same issue.

private void displayMessages(){

    final Set<ChatMessage> mSet= new HashSet<ChatMessage>();
    mChat = new ArrayList<>();

    mDBRootRef.child("messages").child(messageSenderId).child(messageReceiverId)
            .addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                    for (DataSnapshot snapshot : dataSnapshot.getChildren() ) {
                        ChatMessage chat = snapshot.getValue(ChatMessage.class);

                        mSet.add(chat);

                    }

                    mChat.clear();
                    mChat.addAll(mSet);

                    MessageAdapter messageAdapter = new MessageAdapter(ChatActivity.this, mChat);
                    mUserMessagesListRV.setAdapter(messageAdapter);



                }

I have also tried .addChildEventListener instead of .addValueEventListener but getting the same issue.

Here is recycyleview initialisation.

    mUserMessagesListRV = (RecyclerView) findViewById(R.id.recyclerview_chat_log);
    mUserMessagesListRV.setHasFixedSize(true);
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
    linearLayoutManager.setStackFromEnd(true);
    mUserMessagesListRV.setLayoutManager(linearLayoutManager);

Here is onBindViewHolder method.

@Override
public void onBindViewHolder(@NonNull MessageAdapter.ViewHolder viewHolder, int position) {

    //mChat is a list declared as private List<ChatMessage> mChat;
    ChatMessage chat = mChat.get(position);
    viewHolder.showMessage.setText(chat.getMessageText());
}
john
  • 2,324
  • 3
  • 20
  • 37
  • Have you tried to comment `mChat.addAll(mSet);`? What is the behaviour in this case? – Alex Mamo Dec 17 '18 at 08:36
  • Because we are clearing the list before mChat.addAll and then adding the set in a list. – john Dec 17 '18 at 12:25
  • Have you tried what I have asked you? – Alex Mamo Dec 17 '18 at 12:34
  • Yeah, still not working – john Dec 17 '18 at 13:09
  • **[This](https://stackoverflow.com/questions/49383687/how-can-i-retrieve-data-from-firebase-to-my-adapter/49384849)** is a recommended way in which you can retrieve data from a Firebase Realtime database and display it in a `RecyclerView` using `FirebaseRecyclerAdapter`. – Alex Mamo Dec 17 '18 at 13:16
  • You can also check **[this](https://stackoverflow.com/questions/48622480/showing-firebase-data-in-listview)** out. – Alex Mamo Dec 17 '18 at 13:17
  • Thanks. Let me check – john Dec 17 '18 at 13:21
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/185386/discussion-between-john-and-alex-mamo). – john Dec 17 '18 at 21:15

2 Answers2

0

Btw it's strange that you didn't get concurrent modification exception. You can't remove from the list while iterating it:

 mChat = new HashSet<>();

  ....

   for (DataSnapshot ds : dataSnapshot.getChildren()) {
            for (DataSnapshot data : ds.getChildren()) { 

               ChatMessage chat = snapshot.getValue(ChatMessage.class);
                mChat.add(chat);
            }
    }
john
  • 2,324
  • 3
  • 20
  • 37
Hichem Romdhane
  • 364
  • 4
  • 15
  • I have tried HashSet but how can I get position in onBindViewHolder? – john Dec 16 '18 at 18:04
  • @Override public void onBindViewHolder(@NonNull MessageAdapter.ViewHolder viewHolder, int position) { ChatMessage chat = mChat.get(position); viewHolder.showMessage.setText(chat.getMessageText()); } – john Dec 16 '18 at 18:05
  • @john you could iterate through your HashSet and put just the strings you want into coordinate arraylists and use those to work your adapter. that would be better in terms of performance than dealing with the object themselves. If you don't want anymore objects, you should put a setPosition() method in each receipt then only take action in the getview if the correct getPosition() object matches the hascode you want but i think the first solution is much more straight-foward – Hichem Romdhane Dec 16 '18 at 18:16
  • Kindly have a look at my onBindViewHolder method (question edited). Am I doing something wrong there? – john Dec 16 '18 at 18:39
  • @john from hashset you can generate that in list after that for example:servicesList.addAll(mSet); – Hichem Romdhane Dec 16 '18 at 18:51
0

Really late to the party, but I've encountered the same problem, and it turned out to be that Listeners were kept attached to the Database reference even when I exited the Activity. So when I would reenter, it would essentially contain 2 listeners doing the same thing, thus duplicating RecyclerView members. Try adding an extra getApplicationContext() argument when attaching a listener.

 mDBRootRef.child("messages").child(messageSenderId).child(messageReceiverId)
        .addValueEventListener(getApplicationContext(), new ValueEventListener() {
           // Do stuff
         }

This way, when you finish() your activity, the listeners attached to that very activity are detached from the database reference.

ForWiz
  • 145
  • 1
  • 1
  • 10