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();
}
}
我正在使用 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();
}
}