聊天Android-Firebase,同步延迟问题



几个月来,我一直使用Firebase作为数据库为Android系统创建聊天。我在这里遵循了这个指南(链接(一开始一切都很好,聊天很好,没有任何延迟。然后,我开始添加其他特殊性,例如消息的显示与否以及参与者的状态(在线和离线(,从那一刻起,三个问题开始特别显现:

1( 当我将聊天活动更改为转到另一个,然后返回聊天时,布局显示为空,没有消息,如果您尝试更改活动,应用程序会自行关闭。我发现我得到了这个错误:

E/RecyclerView:未连接适配器;跳过布局

这些文件构成了与聊天相关的部分:

MessageChat.java

public class MessageChat {
private String sender;
private String receiver;
private String msg;
private String currenttime;
private boolean isseen;
public MessageChat(String sender, String receiver, String msg, String currenttime, boolean isseen){
this.sender = sender;
this.receiver = receiver;
this.msg = msg;
this.currenttime = currenttime;
this.isseen = isseen;
}
public MessageChat(){}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getReceiver() {return receiver;}
public void setReceiver(String receiver) { this.receiver = receiver;}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getCurrenttime() {
return currenttime;
}
public void setCurrenttime(String currenttime) {
this.currenttime = currenttime;
}
public boolean isIsseen() {return isseen;}
public void setIsseen(boolean isseen) {this.isseen = isseen;}
}

消息适配器.java

public class msgAdapter extends RecyclerView.Adapter<msgAdapter.MsgViewHolder> {
public static final int INT_TYPE_LEFT = 0;
public static final int INT_TYPE_RIGHT = 1;
private static List<MessageChat> mChat;
private static Context context;
private FirebaseUser fuser;
public msgAdapter(List<MessageChat> msg, Context context) {
this.mChat = msg;
this.context = context;
}
@Override
public msgAdapter.MsgViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == INT_TYPE_RIGHT) {
View view = LayoutInflater.from(context).inflate(R.layout.right_message, null);
msgAdapter.MsgViewHolder msgViewHolder = new msgAdapter.MsgViewHolder(view);
return msgViewHolder;
}else{
View view = LayoutInflater.from(context).inflate(R.layout.left_message, null);
msgAdapter.MsgViewHolder msgViewHolder = new msgAdapter.MsgViewHolder(view);
return msgViewHolder;
}
}
@Override
public void onBindViewHolder(final msgAdapter.MsgViewHolder holder, final int position) {
MessageChat msg = mChat.get(position);
holder.show_msg.setText(msg.getMsg());
if ((position == mChat.size()-1) && msg.getSender().equals(fuser.getUid())){
if (msg.isIsseen()){
holder.tv_seen.setText(" Seen ");
holder.tv_seen.setVisibility(View.VISIBLE);
}else {
holder.tv_seen.setText(" Sent ");
holder.tv_seen.setVisibility(View.VISIBLE);
}
}else{
holder.tv_seen.setVisibility(View.GONE);
}
}
@Override
public int getItemCount() {
return mChat.size();
}
public static class MsgViewHolder extends RecyclerView.ViewHolder {
TextView username, show_msg, tv_seen;
public MsgViewHolder(final View itemView) {
super(itemView);
show_msg = (TextView) itemView.findViewById(R.id.show_msg);
tv_seen = (TextView) itemView.findViewById(R.id.tv_seen);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// item clicked
MessageChat msg = mChat.get(getAdapterPosition());
String ctime = msg.getCurrenttime();
TastyToast.makeText(context, ctime, TastyToast.LENGTH_LONG, TastyToast.INFO);
}
});
}
}
@Override
public int getItemViewType(int position) {
fuser = FirebaseAuth.getInstance().getCurrentUser();
if (mChat.get(position).getSender().equals(fuser.getUid())){
return INT_TYPE_RIGHT;
}else{
return INT_TYPE_LEFT;
}
}
}

在互联网上,我发现了许多答案,可以通过以下方式解决这个问题,取代这个:

View View=LayoutInfrater.from(context(.fulle(R.layout.right_message,null(;

到此:

View View=LayoutInfrater.from(context(.fulle(R.layout.right_message,parent,false(;

但就我而言,我只是在一部漫画和另一部漫画之间有空位的情况下进行了一次失败的聊天。

Homefragment.java

public class HomeFragment extends Fragment {
private HomeViewModel homeViewModel;
private View v;
private ImageButton btn_send;
private EditText et_send_mex;
private DatabaseReference reference;
private msgAdapter mAdapter;
private List<MessageChat> mChat;
private RecyclerView recyclerView;
private FirebaseUser user;
private String Uid, Oid;
private static final String sId = "xyz1";
private static final String pId = "xyz2";

ValueEventListener seenListener;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
homeViewModel =
ViewModelProviders.of(this).get(HomeViewModel.class);
// Inflate the layout for this fragment
v = inflater.inflate(R.layout.fragment_home, container, false);
btn_send = v.findViewById(R.id.btn_send);
et_send_mex = v.findViewById(R.id.et_send_mex);
recyclerView = v.findViewById(R.id.rv_mex);
recyclerView.setHasFixedSize(true);
LinearLayoutManager llManager = new LinearLayoutManager(getContext());
llManager.setStackFromEnd(true);
recyclerView.setLayoutManager(llManager);
user = FirebaseAuth.getInstance().getCurrentUser();
Uid = user.getUid();
btn_send.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// notify = true;
String m = et_send_mex.getText().toString();
if (!m.equals("") || !m.equals("n")){
if (Uid.equals(pId)){
sendMessage(Uid,sId,m);
}else if (Uid.equals(sId)){
sendMessage(Uid,pId,m);
}
}
}
});
readMessage();
return v;
}

private void seenMessage(final String senderId){
reference = FirebaseDatabase.getInstance().getReference("chats");
seenListener = reference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot: dataSnapshot.getChildren()){
MessageChat msgchat = snapshot.getValue(MessageChat.class);
if (msgchat.getReceiver().equals(user.getUid()) && msgchat.getSender().equals(senderId)){
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("isseen", true);
snapshot.getRef().updateChildren(hashMap);
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
private void sendMessage(String sender, String receiver, String message){
reference = FirebaseDatabase.getInstance().getReference();
HashMap<String, Object> hashMap = new HashMap<>();
final Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
month = month+1;
int day = c.get(Calendar.DAY_OF_MONTH);
int hour = c.get(Calendar.HOUR_OF_DAY);
int sec = c.get(Calendar.MINUTE);
String dt = day+" - "+month+" - "+year+", "+hour+":"+sec;
hashMap.put("currenttime", dt);
hashMap.put("sender", sender);
hashMap.put("receiver", receiver);
hashMap.put("msg", message);
hashMap.put("isseen", false);
reference.child("chats").push().setValue(hashMap);
et_send_mex.setText("");
}
private void readMessage (){
mChat = new ArrayList<>();
mAdapter = new msgAdapter(mChat,getContext());
recyclerView.setAdapter(mAdapter);
reference = FirebaseDatabase.getInstance().getReference("chats");
reference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
mChat.clear();
for (DataSnapshot snapshot: dataSnapshot.getChildren()){
MessageChat chat = snapshot.getValue(MessageChat.class);
mChat.add(chat);
if (!chat.getSender().equals(Uid)){
Oid = chat.getSender();
seenMessage(Oid);
}
}
mAdapter.notifyDataSetChanged();
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
// user status
private void status(String status){
user = FirebaseAuth.getInstance().getCurrentUser();
reference = FirebaseDatabase.getInstance().getReference("Users").child(user.getUid());
HashMap<String, Object> hashMap = new HashMap<>();
final Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
month = month+1;
int day = c.get(Calendar.DAY_OF_MONTH);
int hour = c.get(Calendar.HOUR_OF_DAY);
int sec = c.get(Calendar.MINUTE);
String dt = day+" - "+month+" - "+year+", "+hour+":"+sec;
hashMap.put("lastaccess", dt);
hashMap.put("status", status);
reference.updateChildren(hashMap);
}
@Override
public void onResume() {
super.onResume();
status("online");
recyclerView.setAdapter(mAdapter);
}
@Override
public void onPause() {
super.onPause();
reference.removeEventListener(seenListener);
status("offline");
}
}

我还被建议在这里添加:

@Override
public void onResume() {
super.onResume();
status("online");
}

以下代码:

recyclerView.setAdapter(mAdapter(;

但结果不佳(也许你可以建议我在这里添加这个部分是否正确,非常感谢(

2( 当我发送消息时,通常需要很长时间才能到达数据库,比方说Firebase并不是一个真正的实时数据库。在这里我没有遇到任何类型的错误,它只是非常缓慢。

3( 后来我还添加了状态更改,只是当应用程序关闭或处于后台时(onPause(((,数据库中的状态设置为脱机,否则为联机。但它通常无法正常工作,可能是应用程序崩溃或延迟影响了这一点。

我仍然可以获得代码的任何其他部分或进行澄清。我提前感谢你的帮助,并为我糟糕的英语道歉,我从去年春天开始就一直在处理这个申请,但我仍然无法解决这些问题。

您要做的第一件事是删除onCreate中的部分。

reference = FirebaseDatabase.getInstance().getReference("chats");
reference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
readMessage();
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});

在这里,您基本上在数据库(聊天(上放置了一个引用,每次它更改时,它都会调用您的函数readMessage,它将始终覆盖您的消息,并将另一个侦听器放在同一位置。请确保您理解,每次更新firebase中的树/路径(聊天(时都会触发addValueEventListener!

您可以简单地将上面的代码替换为:

readMessage();

这样就可以确保它正在监听你的数据库。我相信firebase并不缓慢,但两位听众可能会推翻他们的结果。

关于下一部分我不是100%,但我相信你可以删除

mAdapter = new msgAdapter(mChat,getContext());
recyclerView.setAdapter(mAdapter);

从onDataChange(在readMessage中(,并将其直接放在创建ArrayList的部分下面。像这样:

mChat = new ArrayList<>();
mAdapter = new msgAdapter(mChat,getContext());
recyclerView.setAdapter(mAdapter);
reference = FirebaseDatabase.getInstance().getReference("chats");

我希望我理解你的问题,我的回答会让你更清楚:(

问候!

最新更新