Android Kotlin: Forecast App 03 - Local Database (Room Entity & Dao) - MVVM Tutorial Course

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in the last episode we made a retrofit service to fetch data from the weather API we also use G Santa convert this data from JSON to cotton objects we could technically only use this retrofit service and create a nice user interface to display all of the data we are currently getting doing this wouldn't be really performant and efficient though what if the user doesn't have an internet connection or do we even really need to fetch data from the server every time the app is launched shouldn't we cache all of this data the answer is yes in this tutorial you are going to learn how to create a local SQLite database using the room library and by the end of this tutorial you will understand terms like entity and data access objects are wise known as dows [Music] hello welcome to resew coder and before we get started with implementing our database let's do a quick fix of current weather entry which we have added in the previous part this is because if I launch the app which we have created from the previous tutorial forecast mvvm has stopped and why is that well when we go over to the lock CAD here and we take a look at our error output so somewhere over here number format exception expected an integer but was 10.5 which is a double at line one column something and its current wind mph so let's see in our current weather entry what type is the wind in miles per hour and for sure it is an integer and we need to fix this to be a double because when we were creating in the last part of this class through the Catlin plugin right because we have created with Garland I a class from JSON plugin and this plugin saw that in the JSON we paste it over here there was just an integer and there for some reason there was an decimal place but when we get data which has the single place for wind and also for our values we are getting a type error because a floating-point number is not an integer so let's fix this this will be double and also when km/h will be double you see temperature Fahrenheit is double but temperature Celsius is an integer pressure in millibars should definitely also be a double just like pressure in inches or something and it feels like Celsius will also be a double let's also change the precipitation to be double so millimeters and also inches and probably also visibility kilometers and also miles and now we should be good to go now let's also go over to the build a cradle for the whole project and we are going to upgrade our Kotlin version because now there is a stable one point 3.0 cotton version so we can remove this RC from here and if you have started working through this tutorial later then I have started the probability is that you won't need to do this change and you can even have some cotton version 1.5 point no what do I know but one point 3.0 stable has even stable coroutine support so that is pretty cool and while we are added let's also upgrade all the plugins so build tools and also navigation save arcs and yeah so hit sync now and now let's take a look if our app still runs properly so let's launch it in an emulator and then we will actually get to creating the database classes and all of that and then now the app is launched and we don't get any errors so everything is working properly so now let's close everything off and what we want to do now is to move a bunch of classes more precisely current weather entry condition and also location over to a new package which will reside in data but we also want to create a new sub package its name will be DB for database so and in this database we want to have these three classes so dition come where entry in also location and let's drag them over to DB and hit refactor and under DB package we want to have two different packages one's name will be entity because we are going to be creating entities in just a little bit and the another package will have name units localized we are also going to get to this package in just a little while and now let's move the condition and current winter entry and also location to the entity package so refactor again and to have all of this nicely separated now we have the base package which is data then we have DB for database stuff and we don't want to have directly response over here because response belongs under the network package so let's create a new package network and let's move the response package under the network package we only want to move package not move everything and hit OK so refactor now we are good to go all right now let's come back to data DB and entity and let's edit the current weather entry which we have actually edited at the beginning of this tutorial because we need it to fix the bunch of things regarding the types of our fields here now we want to make an entity out of this class but before we do that let's actually delete some of the properties which are residing in this class that's because we aren't gonna be needing them and if we delete something which is not needed when the JSON is being parsed by the jisan library and json library doesn't see that this class has last updated epoch because we delete it right like this gee son doesn't throw any error it just ignores this property which is deleted and it doesn't care so we can safely delete even last updated because we aren't gonna need it in this tutorial series we only need the temperatures is day we also need the condition and also we mph and kph we aren't gonna need to wind in the degrees but we are only going to need the wind direction then we also aren't gonna be working with pressure so we can delete even these two properties and also we aren't gonna need humidity and also clouds so let's delete them too and that's about it so these are all of the fields that we are actually gonna be using in this tutorial series and all the other fields which we have just deleted can be safely ignored now we want to make an entity out of this class and entities are basically tables in the SQLite database so we want to annotate this class with an entity annotation which is from Android X room library and we also want to set the table name for this entity and the name of the table for current weather entry will be current weather and the table with the name current weather will have columns which will contain temp si temp F is day condition and all of those are properties they're going to be columns in our database table which is called current weather but we have one problem room database and actually SQLite database because room is just a wrapper on top of the SQLite database and SQLite can only store primitive data types so for example double and integers and also strings it can store that but it cannot store condition for example because condition is a custom class and it contains text icon in code so we need to be able to fit objects of type condition inside our table in the SQLite database and to do this we need to annotate this condition with an attribute embedded which is also from Android X room and we also want to prefix this these fields with condition and underscore so in our database the condition object will not we'll be an object while it will be in three separate fields and their names will be condition underscore and text and then also condition underscore icon and condition underscore code so we are actually going to somehow unroll our condition objects into just three simple fields which can be stored because those fields and conditions class are only primitive types because this current weather entry class is now an entity we need to add one property to this class and that is a primary key a primary key can be set to be any property but we are going to create a special property for our primary key and its name will be ID so let's create VAR ID it will be of type integer and we will set it to be a primary key so let's also just simply annotate this property and we are going to set auto-generate to be false primary piece are used to identify all of the different entities which are in our table but in our case there can be only one instance of current weather entry in our database because it doesn't make sense to have two current weather entries because hey there is only one current weather not to count weathers right this means that we can actually assign a constant primary key so a constant ID to our entity class current weather entry because there can be only one of them and for that reason we always know which we want to get we only want to get the one that is present in the database there is no other current weather entry only one instance of it is present in the database at any given time so now let's create a constant for the ID so Const VAR current weather ID and it's going to be equal to zero and whenever we want to get the current weather from the database we know that we can find it with this ID which is zero now let's assign this idea to be current wear ID and this is also the reason why we set auto-generate to be false for our primary key because we don't want the room library to generate it for us because it's constant so generating it would be actually counterproductive all right now let's take a closer look at the current weather entry class we can see that there is temperature in Celsius and also in Fahrenheit there is also miles per hour and kilometers per hour millimeters and also inches but the thing is that the user using our app doesn't want to see the values in millimeters and also inches at the same time we will let the user decide which values he wants to see so Imperial or metric and then we'll display only those values so it's actually kind of wasting of the resources because we need to somehow retrieve all of this data and store it in a memory and also if we are using some ListView the recycler view will have more data to deal with and all of that and also classes which have data which is not currently needed are just harder to work with for that reason we are going to create a separate set of classes which will be Imperial and metric current weather entries we will use those classes to retrieve only the proper field so for example only Celsius or only Fahrenheit whenever we are actually retrieving from the database we will want to have an imperial and also the metric current weather entry under the unit localized package even though they are Imperial and metric they share a lot of common things because of this we are first going to create an interface unit specific current weather entry and then the metric and imperial caramello entries will only implement this interface so let's create a new car LAN interface under the package unit localized and this one's name will be unit specific current weather entry and I'm going to cheat a bit and paste the code in here because I think that it's quite boring to see me just create a bunch of properties and member that you can get the code from the link in the video description which is going to take you to reso coder comm so you can just freely paste it from there and you will be good to go alright so here we have it we will have only temperature condition text and icon URL wind speed wind direction precipitation volume feels-like temperature and also visibility distance you can probably also notice that the field or property names are more clear and nice in this unit specific current weather entry and that's because we are going to use some annotations in the actual classes and not this interface so we will actually get the field call or property called temp C but we can call it nicely like temperature in the code which we'll be using throughout the app all right now under unit localized let's create another class and its name will be imperial current weather entry all right Leslie these curly braces and we are going to make it inherit from unit specific current letter entry or actually implement not inherit because you can only inherit from a class and implement an interface but it's pretty much the same thing now we have a squiggly line because we don't override the members of unit specific current weather entry so let's hit alt enter and we want to implement as constructor parameters and we want to implement all of the fields or properties and now to make this work we need to tell the imperial current weather entry what is the name of the temperature property in our normal classic current weather entry and for imperial we want to have the temperature to be in Fahrenheit so the name of the property which we want to get from the database is temp F so we can copy temp F which stands for temperature in Fahrenheit and go over to imperial current weather entry and we want to annotate this property with column m for hope and info for this property will be that its name in the database which we want to get from the table is temp F so let's paste it over here and we basically want to do this for every single property that we have here so I am again going to cheat a bit and paste the code in here and then come back and tell me what I did all right so here we go condition text it's still just condition text it doesn't change because there is no Fahrenheit or Celsius in condition text the same goes for a condition icon and remember that we are prefixing with condition because the condition is an embedded property here so everything inside the condition is prefixed with condition and underscore then we have for the wind speed we have went in miles per hour when Direction doesn't localize well because it's just a direction and then the precipitation is in inches feels like it's also in Fahrenheit and the visibility is in miles all right now let's do the same thing for metric current weather entry so new class and here I just pasted everything in so we have temperature in Celsius and also kilometers per hour and millimeters and again Celsius and kilometers again you can get the code from the link in the video description and just one last thing to notice here is that imperial and current weather entries are not entities themselves they're only classes and actually imperial current weather entry should be a data class and not a classical class all right so these are not entities but they are only classes which we can get from our database the only entity so entity is something that you actually store in the database is the normal current weather entry which is not localized so in the database everything will be stored so also to Celsius and Fahrenheit and miles and kilometers those fields will be stored in the database and only once we want to get the stuff from the database we are going to be using Imperial or metric current where entry and we need to actually create a way in which we are going to get all of the data from the database and the way that we are going to do it with room is through data access objects otherwise known as simply douse so let's create a new data access object for current weather under the DB package directly so new Kotlin class we're actually not class but an interface here because those are always interfaces when you are using the roomed library and it's name will be current weather Dao because it's a dioxis object we want to annotate it with Dao and we need to create a set of operations that we can do with the table called current weather which contains entities of type current weather entry so we obviously want to be able to add a new current weather entry to the database so we're going to create a function absurd an absurd simply stands for update or insert at the same time so if it's already something there we're just gonna update it because we actually have only one current weather and three present in the database at any given time as I explained previously and if there is no current weather entry yet we are just going to simply insert it so we want to absurd weather entry of type current weather entry and we want to annotate this function with at insert and the on conflict strategy will be on conflict strategy dot replace and because it's replaced whenever there is a conflict which will be pretty much always because a conflict happens when we have two instances of current weather entry which have the same ID and basically all of the instances which we have of Karen where entry will have the same ID because it's by design because their IDs are constant and they are all zero as specified down here so we are always going to have a conflict so always when we want to add a new wear entry and there is already one present we're gonna get a conflict and we are going to simply replace the old one with the new and we're entry and we want to have two other functions one is forgetting metric and the inner one is forgetting Imperial weather so fun get wetter metric this will return live data we're going to get to that later in this tutorial series but live data is just a pretty cool data type which you can observe for changes so whenever the current weather changes in the database the live data will change to so we will be notified about this change and we can observe it from other classes which are dealing with the UI or also from the repository you are just going to learn a lot of things in this tutorial so let's now bog you down now and we'll get to it later so we want to return live data and the generic type of this live data will be metric car and where entry and also we want to annotate this function with add query and this query will select everything from current weather wear ID is and let's interpolate now so current weather ID which is the constant from and let's import it the constant from this class car where your entry is right over here and then let's copy all of this and paste it below but instead of metric car water entry we are going to return imperial current weather entry and let's also import it also change the name from guru error metric to get where imperial awesome so now we have a way to insert and update and also get where a metric and get whether imperial from our database we are getting the weather with a query and the query is an SQLite query where we are selecting everything which is basically only one thing because there is only one thing present at any given moment and we are getting it from Karen weather which is the name of the table which we have created in the current where entry entity right over here and then we want to get only that thing which has an ID of Karen I D and our calendar entry always has ID of current wearer ID all right now the last thing that we want to do in this tutorial is to create a forecast database class under DB so let's create a new count line class forecast database it's gonna be an abstract class and it's going to be annotated with app database the entities of this database will be an array of currently only one entity which is current weather entry and we want to provide it with a class and also the version of this database is currently one also forecast database will inherit from room database current weather Dao is currently only an interface and we will let the database class create a real instance of this interface because interfaces don't have any implementation but classes do and forecast database will create that implementation in the form of a class for us and for the forecast database to create an implementation of our current weather Dao we need to specify it over here as an abstract function current weather dowel which will return an instance of current wear down and what's returned from this function will be actually implemented current weather Dao and then forecast database will also have a companion object this is because a database needs to be a singleton because it doesn't make sense to have multiple instances of a database at the same time also the first time that you create an instance of this forecast database we want to build the database with a special method call through room library so we're going to implement all of that functionality right now first we are going to create private var instance which will be of type forecasts database and it will be knowable and will be no at first and we also need to tell that this property is volatile so all of the threats will have immediate access to this property this is what this volatile stands for we also want to have a lock object because we are going to be using threads so private Val lock will be equal to instantiate it any it doesn't really matter what type this lock object is is basically just a dummy object to make sure that no two threats are currently doing the same thing because then it could happen that we have actually two instances at the same time because two threats are working in parallel and it's all messed up right then we are going to create operator fun invoke just as in the previous tutorial where we created this invoke operator fun in the epics aware API service so operator fun invoke this will accept a context and here we first want to check if instance is not null and if it is not no we want to return it straight away if it is null we want to call a synchronized block of code the lock is the lock object that we have just created and in this synchronized block of code we want to again check if instance is already initialized so instance and also no coalescing a prayer and if it is already initialized we again want to return it directly from here and if it is not we want to initialize it now in this part of code and we are going to create another function which will actually initialize our database it will be a private fun built database it will also get a context and here we want to get room class and on this class we want to call database builder to get the builder the context we want to pass in is an application context so even if this context is the context of a fragment we are going to get the context of the whole application and then we also want to pass in the class of our database class so forecast database class the Java and we also want to specify the database name which is also stored on the local store in our case the name will be simply forecast da DB and then finally we want to call built on this builder and now let's go back to invoke and if it's not initialized this instance we want to initialize it over here so we want to call built database and pass in the context and also whatever is returned from this build database we want to set the instance to be equal to it so we want to set instance to be equal to it all right then that's it for this part of the tutorial series in which you are learning how to use all of the best practices and all of the latest libraries to create a forecast application for Android we didn't create anything tangible in this part because we actually need to also create some kind of a foundation to build off of before we can have something nice and tangible which we can launch on an emulator or on a device so subscribe to this channel and also hit the bell button not to miss any future parts of this tutorial series where we are actually gonna be creating some tangible stuff which you will be able to see if this video helped you to understand the room library and also how to create a database how to create a data access objects and also entities and all of that stuff give this video a like and also share it leave a comment if you have anything to say follow me on Instagram Facebook and Twitter and see in the next video [Music]
Info
Channel: Reso Coder
Views: 37,252
Rating: 4.962213 out of 5
Keywords: resocoder, tutorial, programming, code, programming tutorial, android, kotlin tutorial, kotlin android tutorial, kotlin, android mvvm, android mvvm tutorial, android mvvm architecture, android mvvm design pattern, android room tutorial, android room database tutorial, android retrofit, android retrofit tutorial, android coroutines, kotlin coroutines, kotlin mvvm, kotlin mvvm android, kotlin android, android room persistence library, room database
Id: SB0UepZ5lT4
Channel Id: undefined
Length: 28min 23sec (1703 seconds)
Published: Sat Nov 03 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.