在聊天应用程序中上次看到 [英] Get Last Seen in chats application

查看:17
本文介绍了在聊天应用程序中上次看到的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 firebase 实时数据库和 firebase 身份验证方法创建了这个聊天应用程序,但我真的很困惑,我不知道如何在聊天应用程序中最后一次看到用户.

这是我在 onCreate 方法中尝试的代码.

 @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_chat_avtivity);mauth = FirebaseAuth.getInstance();currentUser = mauth.getCurrentUser();String onlineID = mauth.getCurrentUser().getUid();UserRefernce = FirebaseDatabase.getInstance().getReference().child("Users").child(onlineID);工具栏 = findViewById(R.id.toolbar5);setSupportActionBar(工具栏);ActionBar actionBar = getSupportActionBar();actionBar.setDisplayHomeAsUpEnabled(true);actionBar.setDisplayShowCustomEnabled(true);LayoutInflater layoutInflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);查看 actionbar = layoutInflater.inflate(R.layout.chats_custom, null);actionBar.setCustomView(actionbar);loadingbar = new ProgressDialog(this);mauth = FirebaseAuth.getInstance();senderID = mauth.getCurrentUser().getUid();sendbut = findViewById(R.id.sendmessage);混乱 = findViewById(R.id.editText2);rootRef = FirebaseDatabase.getInstance().getReference();messagereceveirid = getIntent().getExtras().get("user_id").toString();messagereceveirname = getIntent().getExtras().get("userrname").toString();messageImagesStorgeRef = FirebaseStorage.getInstance().getReference().child("Messages_Pictures");namuser = findViewById(R.id.textView3);lastseen = findViewById(R.id.timestamp);circleImageView = findViewById(R.id.imagechatsCustom);messageAdaptet = new MessageAdaptet(messageslists);usermessgerlis = findViewById(R.id.messages);linearLayoutManager = new LinearLayoutManager(this);usermessgerlis.setHasFixedSize(true);usermessgerlis.setLayoutManager(linearLayoutManager);usermessgerlis.setAdapter(messageAdaptet);获取消息();namuser.setText(messagereceveirname);rootRef.child("Users").child(messagereceveirid).addValueEventListener(new ValueEventListener() {@覆盖public void onDataChange(@NonNull DataSnapshot dataSnapshot) {final String online = dataSnapshot.child("online").getValue().toString();最终字符串 img = dataSnapshot.child("User_image").getValue().toString();Picasso.get().load(img).networkPolicy(NetworkPolicy.OFFLINE).into(circleImageView, new Callback() {@覆盖公共无效 onSuccess() {}@覆盖public void onError(Exception e) {Picasso.get().load(img).into(circleImageView);}});如果(在线.等于(真")){lastseen.setText("在线");} 别的 {长时间 = Long.parseLong(online);}}@覆盖public void onCancelled(@NonNull DatabaseError databaseError) {}});sendbut.setOnClickListener(new View.OnClickListener() {@覆盖公共无效onClick(查看视图){发信息();}});}

任何想法或替代方法将不胜感激.

解决方案

您要求的最后可见功能也称为 呈现系统.好消息是,您可以在 Firebase 实时数据库中找到一个名为 onDisconnect() 的方法,它可以帮助您实现这一目标.当您将处理程序附加到 onDisconnect() 方法时,当服务器检测到客户端已断开连接时,您指定的写入操作将在服务器上执行.

这里你可以找到官方文档了解如何管理在线状态系统.

这实际上是它在代码中的样子:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference("disconnectmessage");//当这个客户端失去连接时写一个字符串rootRef.onDisconnect().setValue("断开连接!");

这是使用 onDisconnect 方法在断开连接时写入数据的简单示例.

要解决 Firebase 的整个 seen 功能,您应该为每个用户添加两个新属性.第一个是 isOnline 并且是布尔类型,另一个是 timestamp ,它是 map.如果要显示用户是否在线/离线,就这么简单:

String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();DatabaseReference isOnlineRef = rootRef.child("users").child(uid).child("isOnline");onlineRef.setValue(true);onlineRef.onDisconnect().setValue(false);

对于第二个属性,请参阅我的回答 post,在这里我解释了如何从 Firebase 实时数据库中保存和检索时间戳.要显示上次看到的时间,只需在当前时间戳和数据库中的时间戳之间进行区分即可.

请注意,这在简单的情况下会起作用,但会开始出现问题,例如当用户设备上的连接快速切换时.在这种情况下,服务器可能需要更多时间来检测客户端消失(因为这可能取决于套接字超时)而不是客户端重新连接,从而导致无效的false.>

要处理此类情况,请查看 官方文档中的示例存在系统,对边缘情况有更详细的处理.

还有一点需要注意的是,服务器可以通过两种方式检测客户端的断开连接:

  1. 当它完全断开连接时(应用程序完全关闭,它调用 goOffline()),客户端向服务器发送一条消息,然后服务器可以立即执行 onDisconnect() 处理程序.

  2. 当它是所谓的dirty disconnect(您驶入隧道并丢失信号,应用程序崩溃)时,服务器仅在套接字连接后才检测到客户端已消失,这可能需要几分钟时间.这是预期的行为,到目前为止我没有学到更好的替代方法.

I have created this chat application with firebase realtime database and firebase authentication methods but i am really confused and I don't exactly know how to get the last seen of user in a chat application.

Here is code that I try in my onCreate medthod .

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat_avtivity);
        mauth = FirebaseAuth.getInstance();
        currentUser = mauth.getCurrentUser();
        String onlineID = mauth.getCurrentUser().getUid();
        UserRefernce = FirebaseDatabase.getInstance().getReference().child("Users").child(onlineID);
        toolbar = findViewById(R.id.toolbar5);
        setSupportActionBar(toolbar);
        ActionBar actionBar = getSupportActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setDisplayShowCustomEnabled(true);
        LayoutInflater layoutInflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View actionbar = layoutInflater.inflate(R.layout.chats_custom, null);
        actionBar.setCustomView(actionbar);
        loadingbar = new ProgressDialog(this);
        mauth = FirebaseAuth.getInstance();
        senderID = mauth.getCurrentUser().getUid();
        sendbut = findViewById(R.id.sendmessage);
        mess = findViewById(R.id.editText2);
        rootRef = FirebaseDatabase.getInstance().getReference();
        messagereceveirid = getIntent().getExtras().get("user_id").toString();
        messagereceveirname = getIntent().getExtras().get("userrname").toString();
        messageImagesStorgeRef = FirebaseStorage.getInstance().getReference().child("Messages_Pictures");
        namuser = findViewById(R.id.textView3);
        lastseen = findViewById(R.id.timestamp);
        circleImageView = findViewById(R.id.imagechatsCustom);
        messageAdaptet = new MessageAdaptet(messageslists);
        usermessgerlis = findViewById(R.id.messages);
        linearLayoutManager = new LinearLayoutManager(this);
        usermessgerlis.setHasFixedSize(true);
        usermessgerlis.setLayoutManager(linearLayoutManager);
        usermessgerlis.setAdapter(messageAdaptet);
        fetchmessage();
        namuser.setText(messagereceveirname);
        rootRef.child("Users").child(messagereceveirid).addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                final String online = dataSnapshot.child("online").getValue().toString();
                final String img = dataSnapshot.child("User_image").getValue().toString();
                Picasso.get().load(img).networkPolicy(NetworkPolicy.OFFLINE).into(circleImageView, new Callback() {
                    @Override
                    public void onSuccess() {
                    }

                    @Override
                    public void onError(Exception e) {
                        Picasso.get().load(img).into(circleImageView);
                    }
                });
                if (online.equals("true")) {
                    lastseen.setText("online");
                } else {
                    long time = Long.parseLong(online);
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
            }
        });
        sendbut.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                sendmessage();
            }
        });
    }

Any ideas or alternative ways would be appreciated.

解决方案

The last seen feature that you are asking for is also known as a presence system. The good news is that you can find in the Firebase Real-time database a method named onDisconnect() that can help you achieve this. When you attach a handler to the onDisconnect() method, the write operation you specify will be executed on the server when that server detects that the client has disconnected.

Here you can find the official documentation for how to manage the presence system.

This is actually how it looks like in code:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference("disconnectmessage");
// Write a string when this client loses connection
rootRef.onDisconnect().setValue("Disconnected!");

This is a straightforward example of writing data upon disconnection by using the onDisconnect method.

To solve the entire seen feature for Firebase, you should add to each user two new properties. The first one would be isOnline and is of type boolean and the other one is a timestamp which is map. If you want to display if a user is online/offline, it is as simple as:

String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference isOnlineRef = rootRef.child("users").child(uid).child("isOnline");
onlineRef.setValue(true);
onlineRef.onDisconnect().setValue(false);

For the second property, please see my answer from this post, where I have exaplained how you can save and retrive the timestamp from a Firebase Real-time database. To display the time from the last seen, just make a difference between the current timestamp and the timestamp from your database.

Note that this will work in simple cases, but will start to have problems, for istance when the connection toggles rapidly on user's device. In that case it may take the server more time to detect that the client disappears (since this may depends on the socket timing out) than it takes the client to reconnect, resulting in an invalid false.

To handle these kind of situations, please take a look at the sample presence system in the official documentation, which has more elaborate handling of edge cases.

One more thing to note is that the server can detect the disconnecting of a client in two ways:

  1. When it's a clean disconnect (the app closes cleanly, it calls goOffline()), the client sends a message to the server, which can then immediately execute the onDisconnect() handlers.

  2. When it's a so-called dirty disconnect (you drive into a tunnel and lose signal, the app crashes), the server only detects that the client is gone once the socket ties out, which can take a few minutes. This is the expected behavior, and there is no better alternative that I've learned so far.

这篇关于在聊天应用程序中上次看到的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆