Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/197.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 聊天机器人-Firebase,同步延迟问题_Android_Firebase_Android Studio_Firebase Realtime Database_Chat - Fatal编程技术网

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

Android 聊天机器人-Firebase,同步延迟问题,android,firebase,android-studio,firebase-realtime-database,chat,Android,Firebase,Android Studio,Firebase Realtime Database,Chat,几个月来,我使用Firebase作为数据库,为Android系统创建了一个聊天室。 我是按照这个指南来的 ()一开始还可以,聊天很好,没有任何延迟。然后,我开始添加其他特殊性,例如消息的显示与否以及参与者的状态(在线和离线),从那一刻起,三个问题开始显现: 1) 当我将聊天活动更改为转到另一个活动,然后返回聊天时,布局显示为空,没有消息,如果您尝试更改活动,应用程序将自动关闭。我发现我遇到了以下错误: E/RecyclerView:未连接适配器;跳过布局 以下是构成聊天室相关部分的文件: Mes

几个月来,我使用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;}
}
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;
    }
}
}
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");
}

}
msgAdapter.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;}
}
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;
    }
}
}
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");
}

}
以下代码:

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) {

    }
});
在这里,您基本上会在数据库(chats)上放置一个引用,每次它发生变化时,它都会调用函数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");
mChat=newarraylist();
mAdapter=newmsgadapter(mChat,getContext());
recyclerView.setAdapter(mAdapter);
reference=FirebaseDatabase.getInstance().getReference(“聊天”);
我希望我理解了你的问题,我的回答会让你更清楚一点:)


你好

非常感谢您的及时回复。不幸的是,您的建议没有多大帮助,即使我确信这是侦听器的问题,但目前还没有解决任何问题,事实上,您的第二个建议甚至不再显示消息列表,因为在创建阵列时移动适配器的分配,这不包含任何内容,因为数组的填充是在onDataChange()中完成的。但是,对于第一部分,仅用readMessage()替换代码的这一部分似乎非常有用。谢谢。等待其他建议。请原谅我迟来的答复,但是您也可以尝试执行上面提到的部分,而不是一直创建新适配器,您可以执行类似于?
mAdapter.notifyItemChanged(…)
;这应该会触发adapterReally油箱的刷新,不幸的是,还添加了这个
mAdapter.notifyDataSetChanged()
onDataChange()
函数中,问题仍然存在。还将更改应用于
onCreateView()
中的
readMessage()
,并删除
reference.removeEventListener(请参见Listener)onPause()中的code>解决了应用程序崩溃问题。但问题仍然是,一旦我出去并返回聊天室活动,屏幕是空的,没有消息,加载消息需要很长时间。向Firebase db发送消息也是如此。我期待得到建议。谢谢。正如djnose所说,首先设置适配器。在onCreateView外部侦听器中调用readMessage(),并删除第一个侦听器。移除mChat.clear();。将新聊天添加到mChats。然后调用适配器的notifydatasetchanged(),您可以签出。非常感谢您的评论和帮助,我在帖子中修改了代码,作为对第一条评论的回应,我报告了更新,但我仍然无法解决问题。当我改变活动,然后回到聊天活动,我得到的空白屏幕没有消息,如果我试图去另一个活动/功能,应用程序崩溃,我收到下面的错误信息。此外,我不明白为什么向firebase数据库发送消息如此缓慢。非常感谢你的帮助