I have been working on a client’s project which involves updating data in real-time and storing in Android’s memory(SQLite) then fetch it whenever needed
The problem arose when I want to use the data, I could not know if what I just fetched is the actual current data. This is a problem because the data is very sensitive…fuel prices.
The solution I came up with was using Room mixed with LiveData and it worked perfectly for my use-case.
Today there will be less talk and more code 😀
Room is an abstraction layer for SQLite, It helps you to perform queries in a simple way. Its a part of Android’s Jetpack
LiveData is also a part of Android Jetpack Library which notifies views when underlying database/data changes its lifecycle aware meaning when the particular activity/fragment is active, it’s only time that it works.
Now I will make a simple Android(Java) App which updates the fuel prices and update the UI in real-time
FIRST CREATE AN ANDROID PROJECT WITH JAVA SUPPORT ( Kotlin Code will come soon)
THEN: import a Room library in Gradle using the following code then Build
implementation "android.arch.persistence.room:runtime:1.1.1" annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
Now we create an SQLite Table and Database using Room
To create a table in Room, you create a Class and name it PetrolPrice.java
To turn that class into a TABLE you add an annotation called Entity on top of it like the following
@Entity public class PetrolPrice { }
The above code shows that we have a Table(in this case Entity) called PetrolPrice.
What do we add after adding a Table? That’s right. COLUMNS
To make columns in Room we create them like this
@PrimaryKey(autoGenerate = true) int id; @ColumnInfo(name = "fuel_price") double fuel_price;
To explain the code above, we have 2 columns called ID and FUEL_PRICE
ID is an integer that I made it Primary Key by annotating it @PrimaryKey and made it autogenerate the ID by itself.
FUEL_PRICE is a column with a double datatype and I made it a Column by annotating it by @ColumnInfo
Now we have to add a constructor, getters and setters…like we do in all models.
In the End, our PETROLPRICE.JAVA class will be like this
PetrolPrice.java import androidx.room.ColumnInfo; import androidx.room.Entity; import androidx.room.PrimaryKey; @Entity public class PetrolPrice { @PrimaryKey(autoGenerate = true) int id; @ColumnInfo(name = "fuel_price") double fuel_price; public PetrolPrice(int id, double fuel_price) { this.id = id; this.fuel_price = fuel_price; } public PetrolPrice() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public double getFuel_price() { return fuel_price; } public void setFuel_price(double fuel_price) { this.fuel_price = fuel_price; } }
Now there is something called Data Access Object or DAO. They are the main component in your Room Database. They process the queries and stuff
You declare them by using interfaces. Now I am making a DAO called PetrolPriceDao.java that will perform CRUD operations (Create, Read, Update, Delete)
PetrolPriceDao.java import androidx.lifecycle.LiveData; import androidx.room.Delete; import androidx.room.Insert; import androidx.room.Query; import androidx.room.Update; import com.nickyrabit.roomwithlivedata.room_db.model.PetrolPrice; import java.util.List; public interface PetrolPriceDao { @Insert Long insert(PetrolPrice c); //WHERE WE ARE FOCUSING ON THIS ARTICLE @Query("SELECT * FROM 'PetrolPrice'") LiveData<List<PetrolPrice>> getAllConstants(); @Update void update(PetrolPrice c); @Query("SELECT * FROM `PetrolPrice` WHERE `id` =:id") PetrolPrice getConstant(int id); @Delete void delete(PetrolPrice c); }
Looking at the above code we are annotating a function which we want the query to do, That’s what’s best in Room!
I have set a LIVEDATA on PetrolPriceList which has the task of alerting all Observer object when there is a change in a particular data in our case, PetrolPrice.
A quick explanation on code above @Query() is an annotation that will hold all SQLite queries because Room can perform only some few basic queries without typing them.
Now let’s Go to Creating a Database, We create a new function called FuelPriceDatabase we will define the tables and database here. By annotations as usual
FuelPriceDatabase.java @Database(entities = {PetrolPrice.class}, version = 1, exportSchema = false) public abstract class FuelPriceDatabase extends RoomDatabase { public abstract PetrolPriceDao constantsDao(); private static FuelPriceDatabase INSTANCE; public static FuelPriceDatabase getAppDatabase(Context context) { if (INSTANCE == null) { INSTANCE = Room.databaseBuilder(context.getApplicationContext(), FuelPriceDatabase.class, "apos-database").build(); } return INSTANCE; } public static void destroyInstance() { INSTANCE = null; } }
Look at the @Database annotation, we have defined the table we made earlier by calling it entities {PetrolPrice.class} you can name as any tables as you like there
VERSION is the version of the table if you alter it you need to add a new version.
exportSchema is used when you want to keep track of the database versions. Turn it off in Production yoooooooo!!!
Inside the code, we have this line inside a constructor which defines the database “Price Database” by using DatabaseBuilder method
Room.databaseBuilder(context.getApplicationContext(), FuelPriceDatabase.class, "price-database").build();
DatabaseBuilder Creates a RoomDatabase.Builder for a persistent database. Once a database is built, you should keep a reference to it and re-use it.
OKAAAY NOW LET’S GO TO THE FAMILIAR MAINACTIVITY.JAVA
What we will do there is to observe the changes in the database then do whatever you want with it
In MainActivity onCreate we have to initialize a Database instance like this
FuelPriceDatabase fuelPriceDatabase; fuelPriceDatabase = FuelPriceDatabase.getAppDatabase(MainActivity.this);
Then we have to attach it to an observer which responds to the LiveData notification signal like this
fuelPriceDatabase.petrolPriceDao().getAllPrices().observe(this, new Observer<List<PetrolPrice>>() { @Override public void onChanged(List<PetrolPrice> petrolPriceList) { //Do whatever you want with the list here..update UI....whatever! } } });
On the above code, I have gained an instance of Database to be able to access the DAO object that will send me to the Function that has LiveData on it. That function will check if there is any change in the specific Dao and it will emit the response which in my case is a list containing all the pricing data.
OnChanged method is called when data is changed.
THAT’S IT!!! CONGRATULATIONS, You have DONE IT!!!
Now you can update the Table from the cloud with Firebase or Manually then when you do, that Observer we have set will be fired…If its lifecycle is dead it wont…untill you go back to that screen again!! isn’t that awesome!!
TO SEE THE FULL CODE WITH UI AND ALL PLEASE GOTO MY GITHUB
Github Github https://github.com/nickyrabit/RoomWithLiveDataAndCoroutine
Instagram: nickyrabit https://www.instagram.com/nickyrabit/
Email: nicky@nickylegnard.com
Facebook: Nicholaus Legnard
LinkedIn : Nicholaus Legnard https://www.linkedin.com/in/nicholaus-legnard-5a2a89b8/
WONDERFUL Post.thanks for share..more wait ..
thank you so much
Oh my goodness! an amazing article dude. Thank you However I am experiencing issue with ur rss . Don’t know why Unable to subscribe to it. Is there anyone getting identical rss problem? Anyone who knows kindly respond. Thnkx
hello, thank you for visiting my page I’m currently working on how to fix this problem