May 14, 2017
Firebase contains a host of features for web and mobile application development. This guide utilizes its powerful realtime database to aid in making connections between users and entities. A brief overview of Firebase's realtime database is described first. The handshaking protocol is then theorized. Finally, the RoyalBikeTaxi (Uber clone) implementation example is studied.
The Firebase Realtime Database essentially abstracts away all the work required in setting up and maintaining your own database for your apps. It will handle data-synchronization, offline usability, and security. For more information, check out the docks The important part to understand is how data is stored, retrieved, and changed. This article assumes you know how to get it up and running.
Data is stored in Firebase as a JSON tree, below shows a view of the RoyalBikeTaxi database on the Firebase console. The available drivers are the ones who are on duty, the drivers represent all the drivers in the system, Jim and Steve are always on duty and so theoretically don't need to be in the system (Jim and Steve are purely fictional riders and do not represent any Jims or Steves in real life, even those who happen to also ride bike taxis).
In Android, data may be stored in the tree as any of the following types:
Reading and writing are simple. First, get an instance of the database, then get a reference to a node. Use the node reference to write data or push keys. Because it is a real-time database, reading is a bit odd, but very powerful. To read from the database you must set up a listener to a node reference. Data is then read once when the listener is attached, and will then fire every time the data at that node or any of its child nodes change. Alternatively, you can set up a listener that only reads once and destroys itself. Below is an example of using Firebase in Android. It refers to the database above, changing some values and listening to changes at certain nodes.
As you can see, Firebase utilizes a very simple but powerful set of rules. Let's dive into some theory about how an application can use these rules to make connections. Specifically, how will one user request connections to a pool of available entities? For example, a user who is hailing a bike taxi will want to try and connect to the closest available drivers.
The main strategy will be for the user to create a connection node in the database and then ask an entity from the pool if they want to join the connection. It is like giving someone the key to a club. They can respectfully decline, or they accept the key and find the club. Once in the club, you can confirm that this is in fact the correct club. This is the handshake that occurs. The user offers a key to a node, the entity accepts it and uses it to connect to the node, then the user confirms the connection and communication is established. This protocol promotes safety when making connections app to app. The sequence of events is broken down as follows:
The user starts in an "Idle" state. From the user's point of view, the entities are defined under the ENTITY POOL node in the database. The user does not necessarily have to live on the database as well. The entities must be accessible to the user; the user should have access to the ENTITY POOL so it can request connections. It may ask for connections randomly, alphabetically, etc. In the case of the bike taxi app, the user will request the drivers by closest distance.
The user starts the connection process by pushing a KEY into the database as a new node. It begins listening to this node, which triggers the handshake() method on attachment. The user state goes from "Idle" to "Requesting."
In the handshake() method, the user state is "Requesting" so the user requests a connection to an available entity from the pool by pushing the KEY onto the CONNECTION_REQUEST node of the entity it intends to connect to. The entity has the option to decline or timeout, in which case the user must either quit or try the next available entity on its list; it is now in the "Searching" state. Because the entity is now receiving a request, it must immediately become unavailable or it will risk concurrent requests.
The entity's listen event on the CONNECTION_REQUEST node triggers. The entity first checks if the value equals "Connected," which is a confirmation from the user that it is connected. If it isn't, then this is a new request so it asks for the confirmation by using the KEY to find the correct node to request a connection to and adds a CONNECTED node, setting the value to the entity's id.
The user's listen event on the KEY node triggers and the handshake() method is run again. In the handshake() method, the user state is "Searching" so the USER checks if it has made a connection by looking at its CONNECTED node. If it does not find the node, it keeps searching for entities. If it finds the CONNECTED node, it checks the ENTITY ID on that node to confirm it was the one it was requesting. If all is good it confirms the connection by pushing the value "Connected" onto the entities CONNECTION_REQUEST node.
A side note: if the methods are set up so that a user can request connections from multiple entities concurrently, here is where it would find out which entity responded the fastest by checking the ENTITY ID on the CONNECTED node. Simple modifications to this general strategy can fit many applications.
The entity's listen event on the CONNECTION_REQUEST node triggers. The entity first checks if the value equals "Connected". This time it will be, so it removes itself from the pool and considers itself connected. The user and the entity have now set up access to the KEY node and can easily communicate from here. In the bike taxi app, this is where latitude and longitude data will be continuously updated for real time tracking.
This general strategy can be modified to fit many applications. This is essentially how the bike taxi app works. The pool of entities being drivers, and the user being someone who is looking for a ride.
The RoyalBikeTaxi application is a demo product for the Royal Bike Taxi company in Savannah, Georgia. A company I worked for briefly in the summer of 2016 as a rider and tour guide. Therefore, the app has some features pertaining to that you can just ignore or change. If you would like to use it as a foundation for your own Uber clone or just download it so you can check it out while you go through this article you can grab it here. It is open-source.
Opening the app will take you directly to a map view of Savannah. Refreshing the drivers will show you who lives in the database as an available driver. I am writing this in Victoria so my pin is shown there in blue. At this point if you request a ride the app will try to connect to Jim and Steve; they won't respond and eventually your request will timeout and fail. The database state is shown as well.
The "Drivers" are all the drivers that can log into the system from the login view. Technically Jim and Steve should be in there but they are made up and don't need to be. To log in, navigate to the login view by pushing the hamburger button and tap on the little guy riding the bike 7 times. Type "Ryan" as the name and "m" as the password, matching what is in the database.
If successful, you will be taken to the login screen. You are now signed up as a driver and your credentials will be added to the database. Of course, my pin (in green) is in Canada.
Using another Android device we can test the handshake protocol by logging in as a driver on one device and requesting a dispatch as a user from a different device. The sequence of events is straight forward. The user requests a ride by pressing the floating action button and confirms the pop up, the driver is notified of the request and accepts. The handshake is made and the two are connected. The user and the driver can now see each other's locations which are continuously updated. Either may end the ride or request at any time.
A quick breakdown of the code is shown below with a helpful (hopefully) trace of what the code is doing. Most of the class has been removed in both examples.
The app utilizes the handshaking protocol well and makes connections as expected. The full application is unfinished so there are a couple bugs. Also, it needs to be tested against a real-world scenario consisting of many users and drivers requesting and making multiple connections concurrently. It needs to handle dropped connections, spotty networks, and imperfect GPS readings. In theory, it works well. Thorough testing would ultimately expose the side effects in this code.
The full app can be found on GitHub. Feel free to grab it and make it better!
|1.0||May 14, 2017||Ryan Whitell||