Book Image

Mastering Firebase for Android Development

By : Ashok Kumar S
Book Image

Mastering Firebase for Android Development

By: Ashok Kumar S

Overview of this book

Firebase offers a wide spectrum of tools and services to help you develop high-quality apps in a short period of time. It also allows you to build web and mobile apps quickly without managing the infrastructure.Mastering Firebase for Android Development takes you through the complete toolchain of Firebase,including the latest tools announced in Google IO 2018 such as Firebase ML-Kit, FireStore, and Firebase Predictions. The book begins by teaching you to configure your development environment with Firebase and set up a different structure for a Firebase real-time database. As you make your way through the chapters, you’ll establish the authentication feature in Android and explore email and phone authentication for managing the on-boarding of users. You’ll be taken through topics on Firebase crash reporting, Firebase functions, Firebase Cloud, Firebase Hosting, and Cloud Messaging for push notifications and explore other key areas in depth. In the concluding chapters, you will learn to use Firebase Test Lab to test your application before using Firebase Performance Monitoring to trace performance setbacks. By the end of the book, you will be well equipped with the Firebase ecosystem, which will help you find solutions to your common application development challenges.
Table of Contents (23 chapters)
Title Page
Copyright and Credits
Dedication
Packt Upsell
Contributors
Preface
9
Application Usage Measuring and Notification, Firebase Analytics, and Cloud Messaging
11
Bringing Everyone on the Same Page, Firebase Invites, and Firebase App Indexing
12
Making a Monetary Impact and Firebase AdMob and AdWords
13
Flexible NoSQL and Cloud Firestore
14
Analytics Data, Clairvoyant, Firebase Predictions
Index

Reading and writing to Realtime Database


Since the nuts and bolts of the Firebase Realtime Database are set up, the next stage is to explore how data can be composed or written to a database tree from an Android application. This section will give points of interest on the most proficient method to write, how to erase database tree nodes, and furthermore, outline a few strategies for taking care of database write errors.

Database reference 

Essentially, a reference to the database is required. Every Firebase project has its own particular devoted Realtime Database items of which can be examined by opening the project inside the Firebase console and picking the Database option. Inside the console, panels can be selected to show data trees set away in the database, the rules outlined for fetching the access, database use estimations, and so on. 

Firebase databases are usually Representational State Transfer (REST) endpoint references, which we will use to add the data. We will understand how to fetch the reference with the following code snippet:

// fetch reference database
FirebaseDatabase mDatabase = FirebaseDatabase.getInstance();
DatabaseReference mDbRef = mDatabase.getReference("Donor/Name");

The preceding code will fetch the reference, on the off chance that the particular path does not exist now, it is composed automatically inside the tree when data is written at that location.

Writing into Realtime Database

Fetch an instance of your database employing getInstance() and reference the location you need to write. You can write most of the primitive data types as they also include Java objects:

// Write a message to the database
FirebaseDatabase mDatabase = FirebaseDatabase.getInstance();
DatabaseReference mDbRef = mDatabase.getReference("Donor/Name");
mDbRef.setValue("Parinitha Krishna");

The following screenshot explains the dashboard changes after running the preceding code:

If you notice that there aren't any changes in the dashboard from the write operation, we shall attach an onFailure callback like the following for identifying what's stopping it:

// Write a message to the database
FirebaseDatabase mDatabase = FirebaseDatabase.getInstance();
DatabaseReference mDbRef = mDatabase.getReference("Donor/Name");
mDbRef.setValue("Parinitha Krishna").addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
        Log.d(TAG, e.getLocalizedMessage());
    }
});

Note

Before we compile the preceding code snippet, we need to change the rules to be true since we are no longer using any authentication service. Go to the Rules tab and change the read and write service to be true. When we do this, remember that the endpoint is publicly accessible by anybody who has the URL:{ "rules": { ".read": true, ".write": true } }

Reading from Realtime Database

After writing the data into Firebase now it's time to read what we have written. Firebase Realtime Database syncs all the data in real time across platforms and devices. So we have an onDatachanged() callback to read the data:

// Read from the database
mDbRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
        // whenever data at this location is updated.
String value = dataSnapshot.getValue(String.class);
        Log.d(TAG, "Value is: " + value);
    }

@Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
    }
});

Structuring the data with objects

Create a model class with constructors and declare a string to fetch the database reference for a unique key to add the list of objects. The model class is as follows: 

public class Users {

private String Name;
private String Email;
private String Phone;

public Users() {
    }

public String getName() {
return Name;
    }

public void setName(String name) {
Name = name;
    }

public String getEmail() {
return Email;
    }

public void setEmail(String email) {
Email = email;
    }

public String getPhone() {
return Phone;
    }

public void setPhone(String phone) {
Phone = phone;
    }

public Users(String name, String email, String phone) {
Name = name;
Email = email;
Phone = phone;
    }

}

Now in the activity class using the DatabaseReference class we can set the object value to Firebase, as follows:

public class MainActivity extends AppCompatActivity {

private static final String TAG = "MainActivity";
private FirebaseDatabase mDatabase;
private DatabaseReference mDbRef;
private String userId;

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

// Write a message to the database
mDatabase = FirebaseDatabase.getInstance();
mDbRef = mDatabase.getReference("Donor/Name");

//Setting firebase unique key for Hashmap list
String userId = mDbRef.push().getKey();
// creating user object
Users user = new Users("Hillary", "[email protected]", "90097863873", "Tokyo");

mDbRef.child(userId).setValue(user);

    }
}

The preceding code will add the object into Firebase as follows: 

Reading the objects from Firebase

To read the object data from Firebase Realtime ValueEventListner() whenever there is an update in the database in onDatachanged callback we can read the data changes:

mDbRef.child(userId).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {

        Users user = dataSnapshot.getValue(Users.class);

        Log.d(TAG, "User name: " + user.getName() + ", email " + user.getEmail());
    }

@Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
    }
});

When the code is executed, it will result in fetching the data tree to your project. It is up to us how we make use of the data. 

Since we are using unique key mechanism the data will be added under the Name reference with a unique identifier: 

Reading value changes 

In Firebase Realtime Database to listen to the data changes, we have addValueEventListener for listening to the multiple nodes. In case you want to check the single value by adding addListenerForSingleValueEvent(), we can do that as well:

mDbRef = mDatabase.getReference("/Donor/name");


ValueEventListener changeListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {

    }

@Override
public void onCancelled(DatabaseError databaseError) {

    }
};

mDbRef.addValueEventListener(changeListener);

When a listener is not required, it should be detached from the database reference object as follows:

mDbRef.removeEventListener(changeListener);

Parsing the DataSnapshot object

In a simple way, DataSnapshot can be accessed through the getValue method. We can use the child() method to reach to a specific path of a snapshot. Consider the following example code snippet that fetches the title:

String title = mDataSnapshot.child("message1").child("title").getValue(String.class);

And all the children can be accessed using the getChildren() method. Consider the following code that is reading all the child details inside a for each loop:

for (DataSnapshot child : mDataSnapshot.getChildren()) {
    Log.i(TAG, child.getKey());
    Log.i(TAG, child.getValue(String.class));
}

Updating data

To update data, we can use the setValue() method by passing updated values. You can likewise utilize updateChildren() by passing the way to update data without exasperating other child nodes:

String newEmail = "[email protected]";
mDbRef.child(userId).child("email").setValue(newEmail);

The following screenshot illustrates the updated value for the email field: 

Writing HashMaps to Realtime Database

By using the updateChildren() method of the database reference class, we can write the HashMap data structure into Firebase Realtime Database. Let's create a HashMap and add different key-value pairs, each should be reflected in the Realtime Database:

// Write a message to the database
mDatabase = FirebaseDatabase.getInstance();
mDbRef = mDatabase.getReference("Donor/Name");

//Writing Hashmap
Map<String, Object> mHashmap = new HashMap<>();

mHashmap.put("Name 1/title", "Ashok");
mHashmap.put("Name 1/content", "Parinitha");
mHashmap.put("Name 2/title", "Krishna");
mHashmap.put("Name 2/content", "Sumuthra");

mDbRef.updateChildren(mHashmap);

The following screenshot illustrates the HashMap writing in the Firebase console:

Realtime Database and lists

Lists are compelling data structures and they help in numerous use cases. Firebase has excellent support for HashMap and lists. Users can append the data according to the unique key from Firebase, or you can create your logic to create a unique identifier. Using the push() method a user can insert the data, and there are many ways to filter and match the data pushed. Let's see how the push() method helps in creating a list. As usual first grab the reference to the database and then using the push() method get the unique key. Using the push() method we can add a new child:

// Write a message to the database
mDatabase = FirebaseDatabase.getInstance();
mDbRef = mDatabase.getReference("Donor/Name");

//Setting firebase unique key for Hashmap list
String key = mDbRef.push().getKey();

mDbRef.child(key).setValue("First item");

Apart from allowing a database to create a list, it is also necessary to receive a data-changed notification from the list. This can be achieved through adding child event listeners. These listeners will notify the app when there is a new child added. We need to implement a couple of callbacks when we use this listener. Most commonly there is the onChildAdded() method when a child is added, and it sends a new data snapshot with data added. Note that onChildChanged() is called when there is an update to the existing node, and onChildRemoved() is called when a child node is removed. However onChildMoved() is called when any alterations change the list order:

ChildEventListener childListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
    }
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
    }
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
    }
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
    }
@Override
public void onCancelled(DatabaseError databaseError) {
    }
};

mDbRef.addChildEventListener(childListener);

There are many ways to perform the query on the list. Firebase has a class named Query to access the database inside the application on specified criteria: 

Query mQuery = mDbRef.orderByKey();

ValueEventListener mQueryValueListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
        Iterable<DataSnapshot> snapshotIterator = dataSnapshot.getChildren();
        Iterator<DataSnapshot> iterator = snapshotIterator.iterator();
while (iterator.hasNext()) {
            DataSnapshot next = (DataSnapshot) iterator.next();
            Log.i(TAG, "Value = " + next.child("name").getValue());
        }
    }
@Override
public void onCancelled(DatabaseError databaseError) {
    }
};

mQuery.addListenerForSingleValueEvent(mQueryValueListener);

Deleting data

To delete data, you can call the removeValue() method onto database reference. You can likewise pass null to the setValue() method, which does the same delete operation:

//Removes the entire child
mDbRef.child(userId).removeValue();
//Passing null to remove the calue
mDbRef.chile(userId).child("name").setValue(null);

// Similarly Hashmap can also be removed
Map<String, Object> mHashmap = new HashMap<>();

mHashmap.put("Name 1/title", null);
mHashmap.put("Name 1/content", null);
mHashmap.put("Name 2/title", null);
mHashmap.put("Name 2/content", null);

The following screenshot shows the Firebase console reaction for the delete operation:

Offline capabilities

At the point when clients are disconnected from the internet, the Realtime Database SDKs employ local cache on the device to store changes. Later when the device comes online, the local data is automatically synchronized to Realtime Database. We can enable disk persistence to save the data offline from the following lines of code:

//Offline support
FirebaseDatabase.getInstance().setPersistenceEnabled(true);