Skip to main content

Firebase - A Real Time Database






 

What is Real Time Database?

A real-time database is a database system which uses real-time processing to handle workloads whose state is constantly changing. This differs from traditional databases containing persistent data, mostly unaffected by time. For example, a stock market changes very rapidly and is dynamic. The Firebase Realtime Database It's a cloud-hosted database powered by Google. Data is stored in JSON format and synchronized in realtime to every connected client(devices). You can build the using their iOS, Android and JavaScript SDKs and all of your clients share one Realtime Database instance and automatically receive updates with any changes in the content of the database.

How does it work?

The Firebase Realtime Database allows you to build rich, collaborative applications by providing secure access to the database directly from client-side code. Data is persisted locally, and even while offline, realtime events continue to fire, it gives the end user a responsive experience. When the device regains connection, the Realtime Database syncs the local data changes with the remote updates that occurred while the client was offline, handling any merge any conflicts automatically. The Realtime Database provides a flexible, expression-based rules language, called Firebase Realtime Database Security Rules, to define how your data should be structured and when data can be read from or written to. If integrated with Firebase Authentication, you can define who has access to what data, and how they can access it. It's a NoSQL database and as such has different optimizations and functionality compared to a relational database. The Realtime Database API is designed to only allow operations that can be executed quickly. This enables you to build a great realtime experience that can serve millions of users without compromising on responsiveness.

Setup

To begin using Firebase you will need to create a free account at https://firebase.google.com/.

  • Create a project
  • Choose add "Add Firebase to your Android app"
  • Enter the app package name (com.antoinecampbell.firebase.demo)
  • Enter the SHA-1 fingerprint from your debug certificate
  • Download the generated google-services.json file and place it into the app/ directory
  • Update the rules for your database to allow reads and writes from all users, as this demo will not cover Firebase Authentication.
    {
      "rules": {
        ".read": "true",
        ".write": "true"
      }
    }
  • The demo app is ready to be launched
  • Optionally, you may bootstrap your database with some records by importing the users-export.json file to your database

App Setup

The first step to getting the app ready to use Firebase is to add Google Play Services to the project. In the root build.gradle file adds the following line to your dependencies (/build.gradle):

classpath 'com.google.gms:google-services:3.0.0'

Next, add the Firebase Realtime Database SDK to your app level build.gradle file dependencies (/app/build.gradle):

compile 'com.google.firebase:firebase-database:9.4.0'

Then, apply the Google Play Services plugin at the bottom of your app level build.gradle file (/app/build.gradle):

apply plugin: 'com.google.gms.google-services'

Finally, we will override the application class to enable Firebase's offline mode before any database references are used (FirebaseDemoApplication.java):

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

Retrieving Data

To retrieve data from Firebase Realtime Database we need to query the path containing the list of users, in this case, the path is "users". The data and its children will be returned when queried so all stored users will be returned from the querying the path "users". The only way to query is asynchronous via listeners which return a snapshot of the data at the time of the event. When a listener has attached a snapshot of the data is sent. The listener will be called whenever data on the path being watched is changed, including its children. One thing to keep in mind when querying data from Firebase Realtime Database is that it's not like your typical database. In the efforts to be as fast as possible, some of the more advanced querying options are not available to you such as; partial text searching, object references, and joining. One solution the Firebase team recommends to deal with these limitations is to denormalize the data. The query below returns the value of the "users" path from the database, which is the list of stored users. Also, the Firebase SDK provides built-in deserialization functionality to parse the data into your POJO.

DatabaseReference database = FirebaseDatabase.getInstance().getReference();
...
database.child("users").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
    List users = new ArrayList<>();
    for (DataSnapshot userDataSnapshot : dataSnapshot.getChildren()) {
        User user = userDataSnapshot.getValue(User.class);
        users.add(user);
    }
    adapter.updateList(users);
}
...
});

There may be cases where you do not want to receive constant updates on data changes and instead simply fetch the data once. To do so, use the addListenerForSingleValueEvent() method instead. In offline situations, data would be returned from the local database if present.

Saving Data

In the demo application, new users are pushed onto the users path. In Firebase, the concept of pushing creates a unique identifier for the new item adding it to the end of the specified path. Data in Firebase Realtime Database is stored as JSON and pushing creates a nested element beneath the specified path. The JSON below shows all the data that is stored for two users.

{
  "users" : {
    "-Krp8OS_w2ctz41LNeLA" : {
      "firstName" : "Raj",
      "email" : "rag@gmail.com",
      "uid" : "-Krp8OS_w2ctz41LNeLA"
    },
    "-KrpUlwUggZl3YnhiQgm" : {
      "firstName" : "Pankaj",
      "email" : "pankaj@gmail.com",
      "uid" : "-KrpUlwUggZl3YnhiQgm"
    },
    "-KrpV9oOPQvuoDg8EHln" : {
      "firstName" : "Vinod",
      "email" : "vinod@gmail.com",
      "uid" : "-KrpV9oOPQvuoDg8EHln"
    }
}

You will notice that the key for each user is duplicated within the user itself. The reason being when Firebase returns the data from the users path, accessing the children of the path will not have a unique identifier as part of the object when deserialized into a POJO. So, during the saving process, the user object is set with the unique identifier returned from the push before saving the contents of the user. Essentially, when saving a user, the identifier for the user is created before the content of the user is saved. This allows for simple deserialization, having the unique identifier as part of the user, removing the need to set the identifier after deserialization.

fab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        User user = new User();
        user.setUid(database.child("users").push().getKey());
        user.setTitle(emailTextView.getText().toString());
        user.setFirstName(firstNameTextView.getText().toString());
        database.child("users").child(user.getUid()).setValue(user);
        finish();
    }
});

Updating Data

Updating your data with Firebase is just like saving, except there is no need to do a push to generate a new key.

fab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        user.setEmail(emailTextView.getText().toString());
        user.setFirstName(firstNameTextView.getText().toString());
        database.child("users").child(user.getUid()).setValue(user);
        finish();
    }
});

Optionally, a completion listener can be passed to the setValue() method to be notified when the data saves to Firebase servers. However, the listener would not be called when in offline mode so anything UI-related that needed to happen after a save may not be executed. In the demo, this completion listener is omitted, and we know the data will eventually get synchronized when the user is back online.

Deleting Data

Much like saving data, removing data from Firebase is rather simple. We remove the path associated with the user, in this case, "users/<uid>". The code below is from the MainActivity in the demo app.

@Override
public void itemRemoved(int position) {
    User user = adapter.getItem(position);
    adapter.removeItem(position);
    database.child("users").child(user.getUid()).removeValue();
}

Recall that the "users" path is being watched by the listener and deleting a user will trigger a call to onDataChange() passing the new list of users to the adapter. However, if the adapter receives a new list of users the removal animation will not get a chance to complete before notifiyDataSetChanged() is called. To keep the UI running smoothly, calls to updateList() are essentially ignored if the data change was made on the user's device. If the change was made externally, by another device or from the Firebase console, the app will just refresh the content.

public void updateList(List users) {
    // Allow recyclerview animations to complete normally if we already know about data changes
    if (users.size() != this.users.size() || !this.users.containsAll(users)) {
        this.users = users;
        notifyDataSetChanged();
    }
}

References

1. https://firebase.google.com/docs/database



Comments

Post a Comment

Popular posts from this blog

Future of Mobile Apps

More than 1 billion smartphones and 179 billion mobile applications downloaded per year, mobile development is certainly one of the innovative and rapidly growing sector. The mobile application market is arguably dominated by Google apps (Gmail, Maps, Search), Social media (Facebook, Instagram, Twitter, Youtube) and Gaming apps (Angry birds, Temple Run). Giants like Walmart, Bank of America and Amazon are using mobile applications for branding, improving customer engagement, direct marketing etc. This trend will continue in 2017 as well. There are lots of opportunities for startups and small companies. 1. AI will attract huge investment Industry analyst firms Granter and Forrester have revealed that there will be a 300% increase in investment in artificial intelligence. This is because business users now have unique and very powerful insights open to them. For example, giants like Facebook, Google and IBM are already investing in technologies (by acquiring startups) that would get ...

Introduction to Kotlin : New Official Programming Language for Android

Kotlin is a statically-typed programming language primarily developed by the team of JetBrains that runs on the Java Virtual Machine and also can be compiled to JavaScript source code or uses the LLVM compiler infrastructure. It's a modern programming language. Development lead Andrey Breslav has said that Kotlin is designed to be an industrial-strength object-oriented language, and a "better language" than Java, but still be fully interoperable with Java code, allowing companies to make a gradual migration from Java to Kotlin. Kotlin can be adopted for both sides of development backend and front end. One of the obvious applications of Kotlin is Android development. Android has announced Kotlin as it's official language in Google I/O 2017. Why I should adopt Kotlin : Although Java is one of the world's most widely used programming languages and is pretty much the official language for Android development, there are many reasons why Java might not always ...

15 Key tips to reduce your Android App Size

Users often avoid downloading apps that seem too large, particularly in emerging markets where devices connect to often-spotty 2G and 3G networks or work on pay-by-the-byte plans. This article describes how to reduce your app's APK size, which enables more users to download your app. Understand the APK Structure Before discussing how to reduce the size of your app, it's helpful to understand the structure of an app's APK. An APK file consists of a ZIP archive that contains all the files that comprise your app. These files include Java class files, resource files, and a file containing compiled resources. An APK contains the following directories: META-INF/:   Contains the CERT.SF and CERT.RSA signature files, as well as the  MANIFEST.MF  manifest file. assets/:   Contains the app's assets, which the app can retrieve using an AssetManager object. res/:   Contains resources that aren't compiled into resources.arsc. lib/:   Contains the co...