Search code examples
androidandroid-recyclerviewnavigationnavigation-drawer

Problem with RecyclerView and Navigation Drawer


I'm doing a Group Chat with Firebase and currently I'm using a RecyclerView to display chat messages and I'm having a problem. When you open the app in the fragmented home and you go to chat activity and start chatting (adding elements to recycler view) all goes fine. But, when you go via the NavigationDrawer to another fragment and get back to the chat fragment using again this Navigation Drawer. When you add one element in the chat it appears all in the blank it just displays the last message. Anybody knows why does this happens?

Here I leave the RecyclerView Adapter Code:

   public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.MessageAdapterViewHolder> {

    private final Context context;
    List<Message> messageList;
    public static final int MSG_TYPE_LEFT = 0;
    public static final int MSG_TYPE_RIGHT = 1;

    public MessageAdapter(Context context, List<Message> messageList) {
        this.context = context;
        this.messageList = messageList;
    }

    @NonNull
    @NotNull
    @Override
    public MessageAdapterViewHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) {
        View view;
        if (viewType == MSG_TYPE_RIGHT) {
            view = LayoutInflater.from(context).inflate(R.layout.fragment_chat_message_sent, parent, false);
        } else {
            view = LayoutInflater.from(context).inflate(R.layout.fragment_chat_message_received, parent, false);
        }
        return new MessageAdapterViewHolder(view);
    }

    @Override
    public int getItemViewType(int position) {
        FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
        assert firebaseUser != null;
        if (messageList.get(position).getName().equals(firebaseUser.getDisplayName())) {
            return MSG_TYPE_RIGHT;
        } else {
            return MSG_TYPE_LEFT;
        }
    }

    @Override
    public void onBindViewHolder(@NonNull @NotNull MessageAdapterViewHolder holder, int position) {
        Message message = messageList.get(position);
        int viewType = holder.getItemViewType();
        if (viewType == MSG_TYPE_LEFT) {
            holder.textViewMessageUsername.setText(message.getName());
            holder.textViewMessageUsername.setOnClickListener(v -> {
                Intent intent = new Intent(context, UserProfileActivity.class);
                Bundle bundle = new Bundle();
                bundle.putString("userId", message.getUserId());
                bundle.putString("username", message.getName());
                intent.putExtras(bundle);
                context.startActivity(intent);
            });
        } else {
            holder.constraintLayoutMessageRight.setOnLongClickListener(v -> {
                AlertDialog.Builder builder = new AlertDialog.Builder(context);
                builder.setMessage(R.string.delete_message)
                        .setPositiveButton(R.string.yes, (dialogInterface, i) -> deleteMessage(position))
                        .setNegativeButton(R.string.no, (dialogInterface, which) -> dialogInterface.dismiss());
                builder.create();
                builder.show();
                return false;
            });
        }
        holder.textViewMessageMessage.setText(message.getMessage());
        holder.textViewMessageTime.setText(message.getCreatedTime());
    }

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

    public static class MessageAdapterViewHolder extends RecyclerView.ViewHolder {
        ConstraintLayout constraintLayoutMessageRight;
        TextView textViewMessageMessage;
        TextView textViewMessageTime;
        TextView textViewMessageUsername;


        public MessageAdapterViewHolder(@NonNull @NotNull View itemView) {
            super(itemView);
            textViewMessageMessage = itemView.findViewById(R.id.textViewMessageMessage);
            textViewMessageTime = itemView.findViewById(R.id.textViewMessageTime);
            constraintLayoutMessageRight = itemView.findViewById(R.id.constraintLayoutMessageRight);
            textViewMessageUsername = itemView.findViewById(R.id.textViewMessageUsername);
        }
    }

    private void deleteMessage(int position) {
        DatabaseReference rootReference = FirebaseDatabase.getInstance().getReference();
        DatabaseReference messagesReference = rootReference.child("messages");
        messagesReference.child(messageList.get(position).getKey()).removeValue();
    }
}

Here I leave the ChatFragment code:

    public class ChatFragment extends Fragment {

    private FirebaseAuth auth;
    private final DatabaseReference rootReference = FirebaseDatabase.getInstance().getReference();
    private final DatabaseReference messagesReference = rootReference.child("messages");
    private User user;
    private List<Message> messages;
    private RecyclerView recyclerViewMessageList;
    private EditText editTextChatSendMessage;
    private ImageView imageViewChatSendMessage;
    private Context context;
    private SharedPreferences sharedPreferences;
    private final Gson gson = new Gson();
    private MessageAdapter messageAdapter;
    private ConstraintLayout loadingLayout;
    private LottieAnimationView lottieAnimationViewLoading;

    public ChatFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = getActivity();
        assert context != null;
        sharedPreferences = context.getSharedPreferences(Constants.sharedPreferencesDocName, Context.MODE_PRIVATE);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_chat, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        init();
        bindUI(view);
        setListeners();
    }

    private void bindUI(View view) {
        recyclerViewMessageList = view.findViewById(R.id.recyclerViewMessageList);
        editTextChatSendMessage = view.findViewById(R.id.editTextChatSendMessage);
        imageViewChatSendMessage = view.findViewById(R.id.imageViewChatSendMessage);
        user = gson.fromJson(sharedPreferences.getString("user", null), User.class);
        loadingLayout = view.findViewById(R.id.loadingLayout);
        lottieAnimationViewLoading = view.findViewById(R.id.lottieAnimationViewLoading);
        setAdapter();
    }

    private void setListeners() {
        recyclerViewMessageList.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
            if (bottom < oldBottom) {
                recyclerViewMessageList.post(() -> {
                    if (messages != null) {
                        recyclerViewMessageList.scrollToPosition(messages.size() - 1);
                    }
                });
            }
        });
        imageViewChatSendMessage.setOnClickListener(view -> {
            if (!TextUtils.isEmpty(editTextChatSendMessage.getText().toString())) {
                final Date currentTime = new Date();
                @SuppressLint("SimpleDateFormat") SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");
                TimeZone timeZone = simpleDateFormat.getTimeZone();
                simpleDateFormat.setTimeZone(timeZone);
                String date = simpleDateFormat.format(currentTime);
                final Message message = new Message(user.getId(), user.getUsername(), editTextChatSendMessage.getText().toString().trim(), date);
                editTextChatSendMessage.setText("");
                messagesReference.push().setValue(message);
                messageAdapter.notifyDataSetChanged();
            }
        });
    }

    private void init() {
        auth = FirebaseAuth.getInstance();
        user = new User();
        messages = new ArrayList<>();
    }

    private void setAdapter() {
        loadingLayout.setVisibility(View.VISIBLE);
        final FirebaseUser currentUser = auth.getCurrentUser();
        assert currentUser != null;

        messagesReference.limitToLast(100).addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
                final Message message = snapshot.getValue(Message.class);
                assert message != null;
                message.setKey(snapshot.getKey());
                if (isNetworkConnected()) {
                    messages.add(message);
                } else {
                    Toast.makeText(getActivity(), R.string.no_network_available, Toast.LENGTH_SHORT).show();
                }
                displayMessages(messages);
            }

            @Override
            public void onChildChanged(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
                Message message = snapshot.getValue(Message.class);
                assert message != null;
                message.setKey(snapshot.getKey());

                List<Message> newMessages = new ArrayList<>();
                for (Message m : messages) {
                    if (m.getKey().equals(message.getKey())) {
                        newMessages.add(message);
                    } else {
                        newMessages.add(m);
                    }
                }
                messages = newMessages;
                displayMessages(messages);
            }

            @Override
            public void onChildRemoved(@NonNull DataSnapshot snapshot) {
                Message message = snapshot.getValue(Message.class);
                assert message != null;
                message.setKey(snapshot.getKey());

                List<Message> newMessages = new ArrayList<>();

                for (Message m : messages) {
                    if (!m.getKey().equals(message.getKey())) {
                        newMessages.add(m);
                    }
                }
                messages = newMessages;
                displayMessages(messages);
            }

            @Override
            public void onChildMoved(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {

            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {

            }
        });
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
        linearLayoutManager.setStackFromEnd(true);
        recyclerViewMessageList.setLayoutManager(linearLayoutManager);
        MessageAdapter messageAdapter = new MessageAdapter(getActivity(), messages);
        recyclerViewMessageList.setAdapter(messageAdapter);
        messageAdapter.notifyDataSetChanged();
        recyclerViewMessageList.scrollToPosition(messages.size() - 1);
    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    public void onResume() {
        super.onResume();
        messages = new ArrayList<>();
    }

    private void displayMessages(List<Message> messages) {
        messageAdapter = new MessageAdapter(getActivity(), messages);
        recyclerViewMessageList.setAdapter(messageAdapter);
        recyclerViewMessageList.scrollToPosition(messages.size() - 1);
        messageAdapter.notifyDataSetChanged();
        loadingLayout.setVisibility(View.GONE);
        lottieAnimationViewLoading.cancelAnimation();
    }

    private boolean isNetworkConnected() {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
    }
}

And finally, I leave the MainActivity code:

    public class MainActivity extends AppCompatActivity {

    private AppBarConfiguration mAppBarConfiguration;
    private FirebaseAuth firebaseAuth;
    private GoogleSignInClient googleSignInClient;
    private SharedPreferences sharedPreferences;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Context context = getApplicationContext();
        sharedPreferences = context.getSharedPreferences(Constants.sharedPreferencesDocName, Context.MODE_PRIVATE);
        firebaseAuth = FirebaseAuth.getInstance();
        GoogleSignInOptions googleSignInOptions = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestEmail()
                .build();
        googleSignInClient = GoogleSignIn.getClient(this, googleSignInOptions);
        ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        setSupportActionBar(binding.appBarMain.toolbar);
        DrawerLayout drawer = binding.drawerLayout;
        NavigationView navigationView = binding.navView;
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        mAppBarConfiguration = new AppBarConfiguration.Builder(
                R.id.nav_home, R.id.nav_chat, R.id.nav_profile)
                .setOpenableLayout(drawer)
                .build();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
        NavigationUI.setupWithNavController(navigationView, navController);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        if (item.getItemId() == R.id.logOut) {
            FirebaseUser currentUser = firebaseAuth.getCurrentUser();
            GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
            if (currentUser != null) {
                firebaseAuth.signOut();
                goToLoginActivity();
            } else if (account != null) {
                googleSignInClient.signOut().addOnCompleteListener(task -> goToLoginActivity());
            }
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        return NavigationUI.navigateUp(navController, mAppBarConfiguration)
                || super.onSupportNavigateUp();
    }

    private void goToLoginActivity() {
        sharedPreferences.edit().clear().apply();
        Intent intent = new Intent(MainActivity.this, LoginActivity.class);
        startActivity(intent);
        finish();
    }
}

I have to mention that nothing is crashing in the debug console. That's why I don't put debug logs.

Edit:

If you don't understand the problem, I've made a video: Click here


Solution

  • To solve your problem you can just remove the OnResume method because you are initializing the array every time you change between fragments and that is the problem.

        public class ChatFragment extends Fragment {
    
        private FirebaseAuth auth;
        private final DatabaseReference rootReference = FirebaseDatabase.getInstance().getReference();
        private final DatabaseReference messagesReference = rootReference.child("messages");
        private User user;
        private List<Message> messages;
        private RecyclerView recyclerViewMessageList;
        private EditText editTextChatSendMessage;
        private ImageView imageViewChatSendMessage;
        private Context context;
        private SharedPreferences sharedPreferences;
        private final Gson gson = new Gson();
        private MessageAdapter messageAdapter;
        private ConstraintLayout loadingLayout;
        private LottieAnimationView lottieAnimationViewLoading;
    
        public ChatFragment() {
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            context = getActivity();
            assert context != null;
            sharedPreferences = context.getSharedPreferences(Constants.sharedPreferencesDocName, Context.MODE_PRIVATE);
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            return inflater.inflate(R.layout.fragment_chat, container, false);
        }
    
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            init();
            bindUI(view);
            setListeners();
        }
    
        private void bindUI(View view) {
            recyclerViewMessageList = view.findViewById(R.id.recyclerViewMessageList);
            editTextChatSendMessage = view.findViewById(R.id.editTextChatSendMessage);
            imageViewChatSendMessage = view.findViewById(R.id.imageViewChatSendMessage);
            user = gson.fromJson(sharedPreferences.getString("user", null), User.class);
            loadingLayout = view.findViewById(R.id.loadingLayout);
            lottieAnimationViewLoading = view.findViewById(R.id.lottieAnimationViewLoading);
            setAdapter();
        }
    
        private void setListeners() {
            recyclerViewMessageList.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
                if (bottom < oldBottom) {
                    recyclerViewMessageList.post(() -> {
                        if (messages != null) {
                            recyclerViewMessageList.scrollToPosition(messages.size() - 1);
                        }
                    });
                }
            });
            imageViewChatSendMessage.setOnClickListener(view -> {
                if (!TextUtils.isEmpty(editTextChatSendMessage.getText().toString())) {
                    final Date currentTime = new Date();
                    @SuppressLint("SimpleDateFormat") SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");
                    TimeZone timeZone = simpleDateFormat.getTimeZone();
                    simpleDateFormat.setTimeZone(timeZone);
                    String date = simpleDateFormat.format(currentTime);
                    final Message message = new Message(user.getId(), user.getUsername(), editTextChatSendMessage.getText().toString().trim(), date);
                    editTextChatSendMessage.setText("");
                    messagesReference.push().setValue(message);
                    messageAdapter.notifyDataSetChanged();
                }
            });
        }
    
        private void init() {
            auth = FirebaseAuth.getInstance();
            user = new User();
            messages = new ArrayList<>();
        }
    
        private void setAdapter() {
            loadingLayout.setVisibility(View.VISIBLE);
            final FirebaseUser currentUser = auth.getCurrentUser();
            assert currentUser != null;
    
            messagesReference.limitToLast(100).addChildEventListener(new ChildEventListener() {
                @Override
                public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
                    final Message message = snapshot.getValue(Message.class);
                    assert message != null;
                    message.setKey(snapshot.getKey());
                    if (isNetworkConnected()) {
                        messages.add(message);
                    } else {
                        Toast.makeText(getActivity(), R.string.no_network_available, Toast.LENGTH_SHORT).show();
                    }
                    displayMessages(messages);
                }
    
                @Override
                public void onChildChanged(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
                    Message message = snapshot.getValue(Message.class);
                    assert message != null;
                    message.setKey(snapshot.getKey());
    
                    List<Message> newMessages = new ArrayList<>();
                    for (Message m : messages) {
                        if (m.getKey().equals(message.getKey())) {
                            newMessages.add(message);
                        } else {
                            newMessages.add(m);
                        }
                    }
                    messages = newMessages;
                    displayMessages(messages);
                }
    
                @Override
                public void onChildRemoved(@NonNull DataSnapshot snapshot) {
                    Message message = snapshot.getValue(Message.class);
                    assert message != null;
                    message.setKey(snapshot.getKey());
    
                    List<Message> newMessages = new ArrayList<>();
    
                    for (Message m : messages) {
                        if (!m.getKey().equals(message.getKey())) {
                            newMessages.add(m);
                        }
                    }
                    messages = newMessages;
                    displayMessages(messages);
                }
    
                @Override
                public void onChildMoved(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
    
                }
    
                @Override
                public void onCancelled(@NonNull DatabaseError error) {
    
                }
            });
            LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
            linearLayoutManager.setStackFromEnd(true);
            recyclerViewMessageList.setLayoutManager(linearLayoutManager);
            MessageAdapter messageAdapter = new MessageAdapter(getActivity(), messages);
            recyclerViewMessageList.setAdapter(messageAdapter);
            messageAdapter.notifyDataSetChanged();
            recyclerViewMessageList.scrollToPosition(messages.size() - 1);
        }
    
        @Override
        public void onStart() {
            super.onStart();
        }
    
        private void displayMessages(List<Message> messages) {
            messageAdapter = new MessageAdapter(getActivity(), messages);
            recyclerViewMessageList.setAdapter(messageAdapter);
            recyclerViewMessageList.scrollToPosition(messages.size() - 1);
            messageAdapter.notifyDataSetChanged();
            loadingLayout.setVisibility(View.GONE);
            lottieAnimationViewLoading.cancelAnimation();
        }
    
        private boolean isNetworkConnected() {
            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
        }
    }