Build Online User Presence System Realtime DB Android/Java

How to build Online User Presence System in Android using Realtime Database


Please Subscribe Youtube| Like Facebook | Follow Twitter

For Kotlin follow this article

Introduction

In this article we will learn how to build online user presence system using firebase real time database in our android app.

Our Example

In our example we have a list of user showing their online status that are connected in our android app through firebase realtime database. Before connecting to our database of online users, app user first needs to register using Firebase Authentication. Then that information will be saved our database. After registration user can see list of other online/offline users.

Online/Offline status is implemented using firebase db reference “.info/connected” which is updated every time the Firebase Realtime Database client’s connection state changes. So we will attach listener to it whenever user connection become active (online) or inactive (offline), we will then update online status value accordingly.

Requirements:

  1. Android Project/App in which Online User Presence  to be implemented
  2. Firebase Project

Note: First you need to create Firebase Project and then connect your app to it. You can follow this article to set it up. Also you need to have knowledge of about Firebase Authentication and Firebase Realtime database, therefore it is recommended to follow this article for realtime db and this article for firebase authentication.

Steps

Follow below steps

1) Integrate Firebase Authentication and Realtime Database in your app

2) Code Online Presence System

3) Run and test your app

1) Integrate Firebase Authentication and Realtime Database in your app

First add firebase-auth , firebase-ui-auth and firebase realtime database library at app level build.gradle file

implementation 'com.google.firebase:firebase-database:19.3.0'
implementation 'com.google.firebase:firebase-auth:19.3.1'
implementation 'com.firebaseui:firebase-ui-auth:6.2.0'

Add FirebaseTheme inside res->values->styles.xml

<style name="FirebaseTheme" parent="Theme.AppCompat.Light.DarkActionBar"> </style>

2) Code Online Presence System

Our main activity screen contain button “ONLINE USERS”, on button click we will check user registration using firebase auth. If user is new then we will popup firebase auth registration and save user info in our db. Else if user is already registered then it will directly go to next activity which displays online status of registered users list.

    public void onlineUser(View view) {
        openOnlineUserList();
    }

    private void openOnlineUserList() {
        if(checkSigInStatus()){
            startActivity(new Intent(this,OnlineUserActivity.class));
        }
        else{
            authenticate();
        }
    }

    FirebaseUser authUser;
    private static final int RC_SIGN_IN = 1;
    private boolean checkSigInStatus() {
        authUser = FirebaseAuth.getInstance().getCurrentUser();
        return authUser != null;
    }

    public void authenticate() {
        // Choose authentication providers
        List<AuthUI.IdpConfig> providers = Arrays.asList(
                new AuthUI.IdpConfig.EmailBuilder().build(),
                new AuthUI.IdpConfig.GoogleBuilder().build()
        );
        // Create and launch sign-in intent
        startActivityForResult(
                AuthUI.getInstance()
                        .createSignInIntentBuilder()
                        .setAvailableProviders(providers)
                        .setTheme(R.style.FirebaseTheme)
                        .build(),
                RC_SIGN_IN);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == RC_SIGN_IN) {
            if (resultCode == RESULT_OK && FirebaseAuth.getInstance().getCurrentUser()!=null ) {
                openOnlineUserList();
            } else {
                Toast.makeText(this,"Sign in Failed. Please Sign in To Continue",Toast.LENGTH_SHORT).show();
            }
        }
    }

Below is xml code for main activity and onlineuser activity respectively

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"
    >

    <Button
        android:id="@+id/change"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Online Users"
        android:gravity="center"
        android:onClick="onlineUser"
        />

</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".OnlineUserActivity">

    <ListView
        android:id="@+id/user_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</LinearLayout>

Now on OnlineUserActivity we will first add the current user to users node in our db if previously not added and then change its online status to online. Then we have attached listener to db ref “.info/connected” which will be called whenever user online status is changed. When user goes offline normally it will take 0-3 minutes to make changes effect. This is achieved using onDisconnect() method, where we have set online status value to offline on disconnect.

After adding user to users node and setting its online status we have called populateUserList() method,  which will read all connected users online status on users node and display list on our listview. We have attached listener to users node so whenever if any user’s online status is changed then its updated value will be reflected in our users’ listview.

private void addToUserList(FirebaseUser user) {
	usersListRef.child(user.getUid()).setValue(new User(user.getDisplayName(),"Online"));
	onlineStatus = db.getReference("users/"+user.getUid()+"/onlineStatus");
	connectedRef = FirebaseDatabase.getInstance().getReference(".info/connected");
	connectedRef.addValueEventListener(new ValueEventListener() {
		@Override
		public void onDataChange(@NonNull DataSnapshot snapshot) {
			boolean connected = snapshot.getValue(Boolean.class);
			if (connected) {
				onlineStatus.onDisconnect().setValue("offline");
				onlineStatus.setValue("Online");
			} else {
				onlineStatus.setValue("offline");
			}
		}

		@Override
		public void onCancelled(@NonNull DatabaseError error) {
		}
	});
}

private void populateUserList() {
	userListValueEventListener = new ValueEventListener() {
		@Override
		public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
			userListItems.clear();
			//first check datasnap shot exist
			//then add all users except current/self user
			if (dataSnapshot.exists()) {
				for (DataSnapshot ds : dataSnapshot.getChildren()) {
					if (ds.exists() && !ds.getKey().equals(user.getUid())){
						String name = ds.child("name").getValue(String.class);
						String onlineStatus = ds.child("onlineStatus").getValue(String.class);
						userListItems.add(name+" status : "+onlineStatus);
					}
				}
			}

			adapter = new ArrayAdapter<String>(OnlineUserActivity.this,
					android.R.layout.simple_list_item_1, android.R.id.text1, userListItems);
			userListView.setAdapter(adapter);
			adapter.notifyDataSetChanged();
		}

		@Override
		public void onCancelled(@NonNull DatabaseError databaseError) {
		}
	};

	usersListRef.addValueEventListener(userListValueEventListener);
}

Below is User java file code

package com.programtown.example;

public class User{
    public String name,onlineStatus;

    public User() {
        // Default constructor required for calls to DataSnapshot.getValue(User.class)
    }

    public User(String name,String onlineStatus) {
        this.name = name;
        this.onlineStatus=onlineStatus;
    }
}

Whole Code

app level build.gradle file

apply plugin: 'com.android.application'
// Add this line
apply plugin: 'com.google.gms.google-services'
android {
    compileSdkVersion 28
    buildToolsVersion "29.0.3"
    defaultConfig {
        applicationId "com.programtown.example"
        minSdkVersion 17
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'

    implementation 'com.google.firebase:firebase-database:19.3.0'
    implementation 'com.google.firebase:firebase-auth:19.3.1'
    implementation 'com.firebaseui:firebase-ui-auth:6.2.0'
}

Style.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="FirebaseTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    </style>

</resources>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"
    >

    <Button
        android:id="@+id/change"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Online Users"
        android:gravity="center"
        android:onClick="onlineUser"
        />

</RelativeLayout>

activity_online_user.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".OnlineUserActivity">

    <ListView
        android:id="@+id/user_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</LinearLayout>

MainActivity.java

package com.programtown.example;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.firebase.ui.auth.AuthUI;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import java.util.Arrays;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onlineUser(View view) {
        openOnlineUserList();
    }

    private void openOnlineUserList() {
        if(checkSigInStatus()){
            startActivity(new Intent(this,OnlineUserActivity.class));
        }
        else{
            authenticate();
        }
    }

    FirebaseUser authUser;
    private static final int RC_SIGN_IN = 1;
    private boolean checkSigInStatus() {
        authUser = FirebaseAuth.getInstance().getCurrentUser();
        return authUser != null;
    }

    public void authenticate() {
        // Choose authentication providers
        List<AuthUI.IdpConfig> providers = Arrays.asList(
                new AuthUI.IdpConfig.EmailBuilder().build(),
                new AuthUI.IdpConfig.GoogleBuilder().build()
        );
        // Create and launch sign-in intent
        startActivityForResult(
                AuthUI.getInstance()
                        .createSignInIntentBuilder()
                        .setAvailableProviders(providers)
                        .setTheme(R.style.FirebaseTheme)
                        .build(),
                RC_SIGN_IN);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == RC_SIGN_IN) {
            if (resultCode == RESULT_OK && FirebaseAuth.getInstance().getCurrentUser()!=null ) {
                openOnlineUserList();
            } else {
                Toast.makeText(this,"Sign in Failed. Please Sign in To Continue",Toast.LENGTH_SHORT).show();
            }
        }
    }

}

OnlineUserActivity.java

package com.programtown.example;

import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.ArrayList;

public class OnlineUserActivity extends AppCompatActivity {


    FirebaseUser user;
    FirebaseDatabase db;
    DatabaseReference usersListRef,onlineStatus,connectedRef;
    ValueEventListener userListValueEventListener;

    ListView userListView;
    ArrayList<String> userListItems;
    ArrayAdapter<String> adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_online_user);

        userListView =(ListView) findViewById(R.id.user_list);
        userListItems = new ArrayList<String>();
        db = FirebaseDatabase.getInstance();
        usersListRef = db.getReference("users");
        user=FirebaseAuth.getInstance().getCurrentUser();
        addToUserList(user);
        populateUserList();

    }

    private void addToUserList(FirebaseUser user) {
        usersListRef.child(user.getUid()).setValue(new User(user.getDisplayName(),"Online"));
        onlineStatus = db.getReference("users/"+user.getUid()+"/onlineStatus");
        connectedRef = FirebaseDatabase.getInstance().getReference(".info/connected");
        connectedRef.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                boolean connected = snapshot.getValue(Boolean.class);
                if (connected) {
                    onlineStatus.onDisconnect().setValue("offline");
                    onlineStatus.setValue("Online");
                } else {
                    onlineStatus.setValue("offline");
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
            }
        });
    }

    private void populateUserList() {
        userListValueEventListener = new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                userListItems.clear();
                //first check datasnap shot exist
                //then add all users except current/self user
                if (dataSnapshot.exists()) {
                    for (DataSnapshot ds : dataSnapshot.getChildren()) {
                        if (ds.exists() && !ds.getKey().equals(user.getUid())){
                            String name = ds.child("name").getValue(String.class);
                            String onlineStatus = ds.child("onlineStatus").getValue(String.class);
                            userListItems.add(name+" status : "+onlineStatus);
                        }
                    }
                }

                adapter = new ArrayAdapter<String>(OnlineUserActivity.this,
                        android.R.layout.simple_list_item_1, android.R.id.text1, userListItems);
                userListView.setAdapter(adapter);
                adapter.notifyDataSetChanged();
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
            }
        };

        usersListRef.addValueEventListener(userListValueEventListener);
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        usersListRef.removeEventListener(userListValueEventListener);
    }
}

User.java

package com.programtown.example;

public class User{
    public String name,onlineStatus;

    public User() {
        // Default constructor required for calls to DataSnapshot.getValue(User.class)
    }

    public User(String name,String onlineStatus) {
        this.name = name;
        this.onlineStatus=onlineStatus;
    }
}

3) Run and test your app

Conclusion

So in this post we have learned how to display/show list of online/offline users in android using firebase realtime database.

Please Subscribe Youtube| Like Facebook | Follow Twitter


Leave a Reply

Your email address will not be published. Required fields are marked *