I began using Firebase Realtime database right at the end of my Final Year of College at a time when a good working project could save you from a lifetime of issues with your Supervisors and Academic board. I had been working on an Android Java project and thus needed a Backend for my project. Looking at the timeline involved, a friend recommended Firebase to me. Since I needed a backend that could manage an all required inclusive tool such as authentication, hosting, storage and at the same time providing a great database structure to store my data, I decided to opt-out of the MySQL world at the time which with its several experienced programmers and went into this new JSON based tool presented by Google.
As a new tool, it was not long before I experienced, the harm of being a first-time user. From countless nights of seeing no results to figuring out ways of making simple queries which would have taken just a few minutes using other database systems, I undertook a journey of pain and stress as experienced by most programmers on their path to explore a new tool and leverage it to the max. This article is thus for anyone who is on the beginning path of using Firebase. Although Google has moved on and made this tool even better with several versions each year and new ways of implementations and improvements such as the inclusion of Firestore, its new scalable Database, and others, Firebase Realtime Database is still used by the majority of Android Programmers due to its tried years of use. It is important for the beginner to understand how this tool works in order not to make assumptions that are brought from using another Database. This article with codes written in Android Java has thus been written to enlist what I learned on the path to discovering what and what not to do in attempting to use Firebase in building Mobile Applications.
First of all, it is important for the beginner to understand that Firebase is an asynchronous API since it makes use of the HTTP client protocol which is synchronous in the sense that every request will get a response but asynchronous in the sense that response takes a long time and multiple operations can be run in parallel. This means that response from your Firebase server may take a long time to load on your screen and although everything may well be put in place, sometimes your application may seem not to respond due to this short time drag. It is also easy for your request to not appear on your screen for some period of time. Again, it is easy for you to miss values if the right implementation is not done. For instance, in the following code, we attempt to bind a Firebase request to our Viewholders.
D/Google Activity: BeforeProductName Hand BagD/Google Activity: AfterProductName nullD/Google Activity: AtProductName Hand Bag
It is easy for one to assume that since productnamesinsnapshot is accessed publicly, it should populate the Viewholder since it is already set in at the ValueEventListener, but this is where the understanding of Asynchronous APIs comes in handy. Because the database attempts to make operations even when operations have not been received, it obtains the value from the ValueEventListener but since it has not received the value yet, it proceeds with the rest of the operation, thus productnamesinsnapshot remains empty. When set to the last holder, it does not populate and renders null. Later the value is received and binds to the second holder with value logged at “AtProductName”.After several attempts at testing frustratingly, I figured it out.
I learned surprisingly here that values outside the Firebase Request are not publicly available hence the need for Callbacks and other implementations before using those values in any part of your Activity. One way was to make all the operations in the OnDataChange() method and so the Viewholder, holder, as seen in the example, was not set outside the ValueEventListener but rather in the OnDataChange() method. This small difference could save you lots of time if you try it that way. Trust me I found out late. This article here provides the best resource online for understanding and solving this issue.
At the first look, Firebase looks very simple. Just pulling values from a list of JSON tree structure and following a sequence of paths to make retrieval, with some key pair values. The Database structure could also seem simple but could end up one of the biggest surprises. Most of the Firebase Documentation normally deals with retrieving values from one node, usually the root node of the database. But practically implementations are more complex than that. Retrieving from child nodes could be a great issue if an understanding is not seen from the way a Firebase sees differently from the way you see it. Let’s check this Firebase Tree Structure:
Retrieving values from this structure means moving to each node at a time. This is where the terminologies come into play. Words like Snapshot, Key could mess up and I needed to figure out what each means. I realized to my great excitement that regularly checking your logs to know precisely what it is retrieving could help prevent assumptions from what you think the Database should and must retrieve. For every node you reference, it retrieves all the child nodes from that reference point.
We can, therefore, retrieve values from this Database using this structure
因此,我们可以使用此结构从该数据库检索值
snapshot.child("name").getValue(String.class);
The easy method may create an easy assumption for the beginner until he begins to go deeper into the node. From the previous example, the routine for retrieving values for products may be:
This is a wrong attempt since Firebase begins from snapshot, Firebase loops to each node in a step by step order and thus several nodes have been missed in this attempt. A request may return null when trying to thus retrieve values from the products node.
We keep looping through the nodes. From each snapshot, we can see the key we retrieved by calling the getKey() method. Here are a few logs to understand what happens when we call for the keys for each snapshot to be displayed.
Hence from example two, notice in our attempt to get the values in the product node, we actually jumped from using snapshot1.getKey() to using snapshot2.getKey() before calling on pid. In fact, snapshot1.getKey() is actually products as shown in the log. So, in traversing the node, we can imagine us making a rewrite of our attempt as:
Models may look that innocent, but I learned that it is very important for one to avoid many problems that come along with Models in Firebase. Model Classes interface with your Firebase Database and as such provide a sort of Key Pair structure to retrieve the information unto your Database.
Taking our Sample Model Class for instance there are some few things to note well.
以我们的样本模型类为例,有几点需要注意。
Have an empty constructor: Make sure you call an empty constructor. Not calling an empty constructor could prove the difference between your happy working and a late-night sleep.
Same name: Although it may look extremely simple and has been specified in many documentations, it is easy to miss this. Your data will not be fetched if the name of your variables does not correspond with the names specified in your Firebase. Make sure the names are consistent. For instance, image is the same as image in our Firebase Database. In fact think of it simply as whatever names are in my Database Tree is going to be the same in my Model class as well, Capiche?
Now let’s check this Firebase Realtime Database tree here:
现在,让我们在这里检查此Firebase实时数据库树:
Do not retrieve the value from Non-Value Nodes: It took me missing a vital hackathon to realize this important thing. When calling from your Model Class avoid adding the name of your Nodes. Firebase does not see it as a point to retrieve values but a place to retrieve a tree of values also known as Hashmap. The best practice is to have, for instance, in this example a string called one. Having a string variable inside your Model Class called “l” could be a problem since the information could be retrieved as a Hashmap and cannot be converted in the way you do not want it, if, for instance, you want to just retrieve a string value.
The “Cannot Convert Object of Type String to HashMap Error” could cause you a lot of sleepless nights.
“无法将字符串类型的对象转换为HashMap错误”可能会导致您不眠之夜。
You Must Be Sure Of Your Input Values
您必须确定您的输入值
For numbers make sure that to avoid having double quotes if you are dealing with numerical figures. Sometimes the value type of what is on your client-side may be different from the value specified in Firebase. I recommend making every number into a string value inside your Firebase Database with double quotes as seen in the previous Firebase Database Tree and manipulating the value in your Android Code with the Integer.parse(value) in Java or whatever language you will like to write in.
Normalization Makes Your Structure Simple And Easy To Deal With
规范化使您的结构简单易用
Countless to say Normalization of your database is so important if you want to avoid several frustrations when retrieving values and also avoid several database complexities as your Database grows with time. Also speed retrieval is also thus important. Many recommendations as to the best practices are specified in https://howtofirebase.com/firebase->不用说,如果您希望避免在获取值时遇到一些挫败感,并且随着数据库随着时间的增长而避免多种数据库的复杂性,那么数据库的规范化就非常重要。 因此,速度检索也很重要。 https://howtofirebase.com/firebase->Listeners and Adapters must be well Handled:
侦听器和适配器必须正确处理 :
Firebase is an API with a lot of Listeners, listening to calls to understand changes and respond to them. One of the ways Listeners are very important is in the authentication. Make sure to understand the best way to authenticate. Also, in attaching adapters such as Recyclerview it is important to know the best way. I have created a simple means to make sure the reader understands the best way to work with listeners.
Now in dealing with your listeners, make sure to call them in the onStart() method, hence your application will start listening immediately the application begins to call.
7. Now with all the right sequence, your app will listen to Firebase, you can also read more on Firebase Listeners and Firebaseadapters to fully comprehend the best way to manipulate it, else you can be left with a blank screen since maybe you seem to jump some vital steps each time. Don't worry you will be just fine!
Make sure to check the version of the Firebase version you are using to know what is the best implementation method. Most documentation follows after a particular version which is updated periodically. So don't be shocked that the amazing YouTube tutorial did not work exactly the way you wanted it to end up!
Finally, be aware of the restriction in writing multiple queries in Firebase Realtime Database. It has certain limitations as compared with Firestore, as shown in https://firebase.google.com/docs/database/rtdb-vs-firestore and thus multiple queries at a time could result in an error. It is thus important to create a unique index in your database. Even trying to sort in descending could feel like rocket science if you don't get the information needed. So let’s see. This is what I learned. In trying to query for multiple query clauses to retrieve tidanduid, we create a unique index of traderuser which contains the two values, thus enabling us to make an effective order. As seen in this query.
With this unique index, you can query for multiple values where it would have been just simple with somewhere clauses somewhere. Anyway, an improvement has been made with Firestore and hence these queries have become way easier.
Conclusion: Using Firebase can sometimes prove a challenge, but understanding how it works enables you to leverage its powerful tools in creating an enterprise application that can help leverage other Google-based platforms and enable your business to accelerate as you get acquainted with its features and with its internal mechanism, whether on Web or on Mobile. You have what it takes but like they always say, “experience is the best teacher”. Happy Firebase Realtime Experience!