Video: #5 Android MVVM Architecture Tutorial – Room Database Setup
Hi Everyone! Welcome back to the MVVM series and in this video we will setup the Room Database in our project. Now again if you want to learn Room in detail then you can click here to go through Android Room Course. Because in this video I will quickly setup the Room. Now the main question is "Why we need Room?". As in our project we are trying to implement the user login feature, so how do we know a user is authenticated. If we talk about web app then there we have a session but in our mobile app we do not have a session, so what we do is we call the API and if we get the response as user authenticated that we are getting here, the user is authenticated if we pass the correct email and password we store the user information in local database. And if a user is stored in the local database we assume the user is logged in.
And we are going to do the same thing in our project. But in terms of security it is really a bad practice. But as we are learning we will do like this. But let me also tell you about what actually happens in production applications. So our API gives a token on successful login, and that is saved and the token is valid for a specific time. And when the user logs out the token is invalidated. But here we are not going to make things complicated so we will just store the user in SQLite database. And to operate the SQLite database I want to use Room here. So enough talking guys, let's get started. But before starting, if you are not already a subscriber, please subscribe to the channel and don't forget to hit the bell icon so that you are always notified about my new videos. So coming back to our project inside our data package I will create one more package here and I will name it db. And I will store all the local database related classes or files here. Inside db I will create a kotlin file or class and I will name it AppDatabase and this is a class, kotlin class.
Then inside this package I will create one more package to store all the database entities. So we have the entities, now inside the entities package I will create one more class to store the user. And let's create kotlin file class and name it User. And it is a class. Because right now in our project we have only one entity and it is our User entity. Now we need to define our User class to map these values that we are getting in the login response. So let's do it. I will make a data class here and this class do not need a body. And to this class I will define all the values that are required for our User. The first thing that we need is a var of type Int and the name of this var is id. So I will name var id of type Int and the initial value would be null. Then again I will define name of type String and the initial value is null. And the same way I will define all the other variables. So we have all the variables that are required to map our User to this class.
Now I will delete this thing we don't need it now. Now as this class is an entity for our Room Database we need to annotate this class with the annotation @Entity. And if you want to change the table name in your room database you can define a table name here. But I don't want to change the table name so I will keep it like this. And above this I will define a constant val and I wil name it CURRENT_USER_ID and for the value I will write 0, as we want to store only the authenticated user in our local database we do not need to make the ID auto increment, because we don't want to store multiple users for now. So for this user table, I will define the primary key as autoGenerate false and I will put the constant value that we defined here. And in case of any conflict I will replace and overwrite the currently saved user, because only the authenticated user is stored in our Application. So there is only one user in the local database. And that is why I will define a primary key here in the class body and I will make it a var and I will name it uid and the type is again Int and the current value is CURRENT_USER_ID and I will make it primary key with the help of @PrimaryKey annotation and I will make it the autoGenerate to false, that's it.
So we have our entity class ready. Now to handle the database operation for this User table we need to create a Dao, which is data access object. So inside our db package we will create one more Kotlin file class, and we will name it UserDao. And because this is a dao we need to create an interface. So let's create interface UserDao and we need to annotate it with @Dao annotation. And that means this interface is a data access object. Now here I will define two functions the first function is to insert or update the user. So I will create fun upsert() that means insert or update. Or you can name your functions anything, the name doesn't matter at all. And inside this function we will pass User, which is our entity so we have the user and this function will return us a Long. So in case a user is successfully inserted we will get the inserted row id with the help of this Long so that is why Long is the return type of this function.
Now this function will perform the insert operation in our database, that is why we need to annotate it with the @Insert annotation. And inside this insert we will define what we need to do when there is a conflict, that means we want to insert the same id again or the same primary key again. So in this case we will right Conflict Strategy which is OnConflictStrategy.REPLACE. So we will overwrite the currently saved user with the new one in case of conflict. Now I will need one more function here and this function will give us back the stored user. So that is why I need to annotate this function with @Query and for the query we will write "SELECT * FROM User WHERE uid = $CURRENT_USER_ID" that we already defined in our entity class.
So we need to import the CURRENT_USER_ID so it is imported from the entities. So we have the annotation now we will create a function fun getUser() and this function will return us a LiveData of type User, that's it. So we have all the functions that are required for our UserDao. Now let's come back to AppDatabase and create our Database. Now whenever you are creating a database class for Room you need to make it abstract and you need to extend RoomDatabase. Then you need to put an annotation which is @Database and inside this annotation you need to define all the entities that you have. So in our case we have only a single entity that is User.class actually User::class, so this is how we define the entities. And this is an array so you can define as many entities as you want. And for the next parameter, we will define the version of our database so in my case it is the first version. Now inside your class you need to create the abstract functions for all your Daos.
So in our case we have only a single Dao. I will create here abstract fun getUserDao() and it will return us a UserDao, which is our interface that we just created. Now after declaring all the Dao functions I will create a companion object to create our AppDatabase and inside the companion object first I will create a private var and I will name it instance and this is the instace of our AppDatabase and the initial value is null and I will make this instace as @Volatile. And @Volatile annotation in kotlin means this variable is immediately visible to all the other threads. So that is why it is @Volatile now after this instace variable I will create a private val LOCK and it is of type Any. And I will use this LOCK to make sure we do not create two instances of our Database. Now we will create an operator fun invoke() and this function will take context because we need context to create the database. So when we create the AppDatabase we will pass the context to this invoke and this invoke will first check if this instance is not null so if this instance is not null it will return the instance and with the help of this operator we can immediately return the instance if it is not null if it is null it will come here and here we will create a synchronized block with this LOCK val that we created.
Inside the synchronized block again we will check if the instance is not null and if it is null then in that case we will call a function that is buildDatabase() and to this function we will pass context, now let's create buildDatabase() first, so here inside the companion object we will create private fun and it is buildDatabase() and it will take context and it will build the database for us so we will write = Room.databaseBuilder() now this databaseBuilder function takes three parameters, the first parameter is the context and we have the context here and when we want to build the database we will use context.applicationContext to always pass the applicationContext. So even if we pass the context from a fragment it will take the applicationContext. Now for the next parameter we need to pass our abstract class that is extending the RoomDatabase so here we will pass AppDatabase::class.java. And for the last parameter we need to pass the database name, so I will create a database named MyDatabase.
db or you can name it anything and then finally we will call the build() function to build our database. Now this function is returning us the database, so we are calling it here to build the database and we are passing the context that we received in this invoke() now we will call also and we will assign the returned value of this buildDatabase that is our database actually to this instance. So we need to write here instance = it. And our database is created. Now we can use this AppDatabase to get the UserDao and then from the UserDao we can save our User to our Database. But for this we need to parse the response because currently we are getting the response in a raw string format, and we will parse the response in the next video. So that is all for this video friends. In the next video we will finally use this Room to save the logged in user. In case you have any difficulties you can let me know in comments. Because it is very important that you complete every lesson of this course successfully. And if you are loving this course then please promote this course to your friends as well. Thanks for watching everyone this is Belal Khan now Signing Off..