RecyclerView 和导航抽屉的问题

Problem with RecyclerView and Navigation Drawer

我正在使用 Firebase 进行群聊,目前我正在使用 RecyclerView 来显示聊天消息,但我遇到了问题。当您在碎片化的家中打开应用程序并进入聊天 activity 并开始聊天(向回收站视图添加元素)时,一切正常。但是,当您通过 NavigationDrawer 转到另一个片段并再次使用此导航抽屉返回聊天片段时。当您在聊天中添加一个元素时,它全部显示在空白中,它只显示最后一条消息。有人知道为什么会这样吗?

这里我留下RecyclerView适配器代码:

   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();
    }
}

这里我留下ChatFragment代码:

    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();
    }
}

最后,我留下 MainActivity 代码:

    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();
    }
}

我不得不提一下,调试控制台中没有任何崩溃。这就是为什么我不放调试日志的原因。

编辑:

如果你不明白问题,我做了一个视频:Click here

要解决您的问题,您只需删除 OnResume 方法,因为每次在片段之间切换时都会初始化数组,这就是问题所在。

    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();
    }
}