Android Display List View from Firebase Database

This is a beginners guide to use Firebase Realtime Database in Android. Firebase is backend as a service which provides easy to use services like realtime database, storage, authentication of users.

In this article we will see how we can use Firebase database to fetch real time data and present in our Android app. Firebase Database is cloud hosted no sql database. Data is synced and can be cached across all devices in realtime. Since it is a realtime cloud database, any changes or updates in the database are reflected in realtime across all the client devices.

We will see how we can display a list of items in Android fetched from firebase database.

Android Setup

  • Create a new android project with empty activity.
  • Open Tools -> Firebase

Android studio firebase connection setup

  • In the Firebase Assistant window click on Realtime Database
  • Click on Save and retrieve data
  • In the next window click on Connect to Firebase

If this is the first time you are setting firebase then connect to firebase will open an authentication window in browser. Go ahead and authenticate

 

 

  • Once authenticated click on Connect to Firebase again to create a new Firebase project.
  • Click on Add the realtime database to your app button in firebase database assistant.

After updating the project build.gradle should have firebase database dependency.

    implementation 'com.google.firebase:firebase-database:16.0.5'

Firebase Database Setup

  • Open firebase console and select newly created firebase project
  • Click database and select realtime database. For simplicity you can select Start in test mode. Let me know in comments if you want to know how to secure your database.
  • For this example I have created a json file that you can import in your database.  Download Targetapi.json

Android Client Code

Pojo Class

package com.codeexa.com.firebasedatabaseexample;

import com.google.firebase.database.IgnoreExtraProperties;
@IgnoreExtraProperties
public class AndroidTargets {
    public String FIELD1;
    public Long FIELD2;
    public String FIELD3;
}

Main Activity

package com.codeexa.com.firebasedatabaseexample;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;

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.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "CodeExa.Com";

    ArrayList<AndroidTargets> mTargetData = new ArrayList<>();
    private RecyclerView mRecyclerView;
    private TargetDataAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        fetchData();
    }

    private void initView() {
        mRecyclerView = findViewById(R.id.recyclerView);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(layoutManager);

        mAdapter = new TargetDataAdapter(mTargetData);
        mRecyclerView.setAdapter(mAdapter);
    }

    private void fetchData() {
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        DatabaseReference myRef = database.getReference();
        ValueEventListener postListener = new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                // Get Post object and use the values to update the UI
                mTargetData.clear();
                for (DataSnapshot single : dataSnapshot.getChildren()) {
                    AndroidTargets target =  single.getValue(AndroidTargets.class);
                    mTargetData.add(target);
                }                // ...
                mAdapter.notifyDataSetChanged();
                Log.e(TAG, "Data received:" + mTargetData.size());
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                // Getting Post failed, log a message
                Log.w(TAG, "fetchData onCancelled", databaseError.toException());
                // ...
            }
        };
        myRef.addListenerForSingleValueEvent(postListener);
    }
}

Adapter Class

package com.codeexa.com.firebasedatabaseexample;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Locale;

public class TargetDataAdapter extends RecyclerView.Adapter<TargetDataAdapter.TargetViewHolder>{

    ArrayList<AndroidTargets> targetsArrayList;

    public TargetDataAdapter(ArrayList<AndroidTargets> mTargetData) {
        targetsArrayList = mTargetData;
    }

    @NonNull
    @Override
    public TargetViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View v= LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.target_row,viewGroup,false);
        return new TargetViewHolder(v);
    }

    @Override
    public void onBindViewHolder(@NonNull TargetViewHolder viewHolder, int i) {
        viewHolder.androidTargetName.setText(targetsArrayList.get(i).FIELD1 );
        viewHolder.androidTargetNumber.setText(String.format(Locale.getDefault(), "API Level: %d", targetsArrayList.get(i).FIELD2));
        viewHolder.androidTargetShortName.setText(targetsArrayList.get(i).FIELD3);
    }

    @Override
    public int getItemCount() {
        if(targetsArrayList == null)
            return 0;
        return targetsArrayList.size();
    }

    public static class TargetViewHolder extends RecyclerView.ViewHolder {
        protected TextView androidTargetName;
        protected TextView androidTargetNumber;
        protected TextView androidTargetShortName;
        public TargetViewHolder(@NonNull View itemView) {
            super(itemView);
            androidTargetShortName= (TextView) itemView.findViewById(R.id.textView2);
            androidTargetName= (TextView) itemView.findViewById(R.id.textView3);
            androidTargetNumber= (TextView) itemView.findViewById(R.id.textView4);
        }
    }
}

activity_main.xml layout

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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.support.v7.widget.RecyclerView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:id="@+id/recyclerView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

Row layout target_row.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/textView2"
        android:textColor="@color/colorPrimary"
        style="@style/Base.TextAppearance.AppCompat.Small"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:gravity="center"
        android:text="@string/textview"
        android:minWidth="100dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textView2"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:id="@+id/textView3"
            android:gravity="center_vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:layout_marginBottom="8dp"
            android:text="@string/textview" />

        <TextView
            android:layout_marginTop="8dp"
            android:id="@+id/textView4"
            android:gravity="center_vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/textview" />
    </LinearLayout>
</android.support.constraint.ConstraintLayout>

Build and run the project. This will display the list saved in realtime database in android recycler view.

Any update in the database data will call ValueEventListener again and the list will refresh automatically.

Enable persistance (Offline usage)

Firebase has a very beautiful feature which is to cache the the data retrieved from the cloud database for offline usage. To enable persistent database enable firebase database persistent flag in Application class.

Extend Application class and add class name in AndroidManifest application tag.

package com.codeexa.com.firebasedatabaseexample;

import android.app.Application;

import com.google.firebase.database.FirebaseDatabase;

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        FirebaseDatabase.getInstance().setPersistenceEnabled(true);
    }
}

Updated AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.codeexa.com.firebasedatabaseexample">

    <application
        android:name=".MyApp"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="GoogleAppIndexingWarning">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

Leave a Reply