2

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.

ZarNi Myo Sett Win
  • 1,353
  • 5
  • 15
  • 37

2 Answers2

2

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.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
0

Create a room database in device. As soon as user opens the chat window, update the room database with the instantaneous date/time. Connect firebase with the room database using firebase sync intentservice and send that date/time to firebase. On the other device (which has send the chat message) the room will sync with firebase and ensure that user see some action when message is read. Refer to the link to sync room with firebase using intent service.

Sushant Somani
  • 1,450
  • 3
  • 13
  • 31