Retrofit Android Tutorial - Make API Calls

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello what is up everyone welcome back to a new video which is a retrofit tutorial video and for those who don't know what retrofit is it is just a library to make API CS to access apis and back ends and in this case we will be accessing this API that uh retrieves for us uh products with their images price and description and more data and R fate is a really easy and straightforward library to to do that in a simple way and yes makes it really simple to do that so this is the Json API that we will be accessing this is its URL it's this dumy Json SL products it's a free one and this is how it's going to look like uh basically a list of products and each product with their uh ID title and other data like uh category and uh description and images and uh here are how they look like in our apps so we access the image es and the title price and description so yes I say let's get started with our app before we get started you can check my Instagram account in which I post uh helpful updates and uh Android tips and uh coding in general you can check it out and uh follow me if you like what I do there so back to our app it's now uh go to our grer do file and see what we need these are the the libraries we need first one is the retrofit so uh this is the main retrofit library or dependency and this is the Json converter so this one just converts this Json let's check it out this Json into a a data class that we can create later and then okay HTTP and login to get uh to get uh the logs and uh then Quil this one is used for loading images you could if you if you came from XML you could imagine it as Glide Glide was a really good library to load images and this is the same Quil is a really easy and straightforward one to load images so just paste these libraries you can find this uh app uh on GitHub and the URL will be in the description and then click Sy now now in our main activity or actually before in our main activity let's just create the packages we need we need uh two packages for this the data which will hold out all the data stuff like making API calls and the API and the repository and the data classes and then the presentation package in which will be the presentation one basically we'll have our view model there and screen uh for this I'm just going to create the screen directly here to just make it simple but yes if you have a bigger app you want to create the screen in your presentation package so let's get started on creating the packages uh the first one is data in which we will have uh another package called Model so inside let's just uh unable this or uncheck that compact to have our packages like this and then create our package our uh data class to create it we don't actually want to create it manually instead what we are going to do is we want to come to our Json uh our Json API and then copy everything just copy everything and then you need a plugin for this this is the plugin that can create data classes out of this one so you don't have to create it by your own so in your uh model just create a new and then cotl data class file from Jone you won't find this if you don't have the plugin and this is how you can get it just go to your uh settings then search for plugins here are plugins and yes just search for for Json to cink class so Json tootling class this one and then install this this uh package here in Marketplace actually and then click install and then you'll have it so in your in our model package click create new uh cotlin data class file from Json and then just paste that Json with copy this is it and let's give it a name like uh and click generate wait a little bit and here they are generated generated uh for our St dat classes the first one for the entire thing which is uh let's have a look here which is for this entire thing which is uh which holds now this list of products and these other things like limit skip in total I guess they are at the very bottom here they are total skipe limit but we don't need those we only interested in this one and then it created for us this one which is the the product itself like the single item which is this one inside a list but I'm going to rename it so this one I'm just going to uh call it now product and then name this one products I guess that's a better name in and this is it now for our model package we just created our packages now in our data we want now to create our API so our API will be just an interface with a function and then res it will do everything will do the implementation for us so this is uh how the API will look like we'll create a new class file we'll call it API or products API whatever you want and choose interface here now in our interface we'll have one suspend function because of course we are making API calls this these are IO operations which block the UI that's why I want need to launch them uh inside the Corine so span function get products list so this is our function and of course it would return return products this one and then we annotate our uh function with a get annotation so retrofit knows what we want to do with this so get and then uh I'm going to do something and then I will explain later so get and then we write products here like this so what is this product B basically will have a base URL right here so WR inside let's create inside a component object so component object uh V or con VA base URL that is going to be our URL but only the base URL so uh the base URL is like until uh from the start to this the ending of the domain name so let's copy that so this is the base URL uh let's check another one for example Instagram the base URL you could imagine it from the start until this uh right here which is the ending of The Domain nameing then whatever comes next is just either paths or queries in our case it's a path while because it's directly slash product which is a path in our case to to to then uh add this path to our base URL we just wred air so what roit will do is it it will use uh this base URL and then add this path to it in case we have uh queries and what queries are we can imagine them as values that can change uh for each user and it most likely would be the API key for example if this API wasn't free and you need to buy or register or create an account for example even if it's free you need to create an account for that and you have a limit and for they to know that you reached your usage limit then you need an Epi key to know who exactly made the Epi call so if this URL had an Epi key it would look it would look like this so we just add this question mark and here we already have this Auto completion here so this is how the API key would look like so a question mark the name of the query and then is equal than the actual value of the query in this case it is an API key and if we had this you may have it like an API key like this or page for example if you need to know for example this is the first page of products and then you want to go to the second page then you need to change the query to do that uh right here right now we only have this path which is an immutable path so it doesn't change but in case we want to have a changeable query then we need to add we need to pass that to the function as a parameter so we just annotate this with a query that comes again from uh retrofit and uh with the name of the query so in this case for example API key and then we create it so it is API key or we create I guess I mean the parameter string that is of type string like this now we just created the query once I call this function then this path will be added to the base URL and then the query uh this one depending or on what I passed basically now I'm going to pass the AP I ke the string for when I call this one and then it will eventually look like this if it's page or a query and then in case we have more than just a query because that's possible that we may have more than a query for example pent than Epi key so to add that we just need this to use this uh end symbol like this and then the new the new one so this is Page Now API key and our API key is uh something like this 1 2 3 4 5 six or something now we already created the API key now we want to create the page page and that is of type integer it might be page it might be anything else but uh yes I'm just trying to explain to you how would this look like if we had queries so these are this is it for queries but in case we have now changeable paths so for example we want to load uh a specific type of products like only tablets or only la laptops then we can add that for example after our product pass so slash now let's say we want uh for example T tablets like this so This Is Now tablet path and uh it it can change so as I said it can be it can be tablets it can be like phones so this one can change and uh it changes depend on what we want but products doesn't change so what is the difference difference between the two PS I mean what is the difference between the two PS in the creation we just uh always need to add that right here because that's a path then it will need to be here so let's say uh the type uh let's say the type now of the device that we want or the products but we can just add it like this because now this one is is not changeable but to make it changeable we just put it inside two brackets like this and then again we need to pass that through our uh function like this as a parameter I mean so annotate this with a path annotation and then we say it is type type path so that uh whatever we pass now will be assigned to this one and uh let's say type here and it is of type string and yes now when I call this one Whatever I I I uh passed as the type like tabletes and then that will be assigned to this one and here we would have tablets or laptops and then now and then after that the page and the API key as queries that can change uh so to know whether that's a a path then if it's a path it just have slash then the path if it is a query then it would look like some something like this page is equal to something or API key is equal to something so this is how uh the URL would look like if we had those and this is how we can access that and of course get the products but in our case we don't have all of that it's just directly like this but I'm just going to keep this function for you in case you want to have a look at it I'm just going to put it down here and uh comment it out because it will give me errors uh so I'm now going to remove these things that I didn't need or I don't need and yes this is enough for our API function these are the query annotation and path annotation I don't need them that's why I'm just going to remove them and now after the API I'm going to create the result class uh basically the result class I'm I'm going to create it and then I'm going to explain it so result which is going to be a SE class basically when we make this API key not interface S Class when when we make this API key we may success on loading the data or we might fail so the an error would occur in case there is no answer connection or something wrong with the API itself or some HTTP exception or whatever so there was an error on loading the data now we need to uh know what happened and we would know what happened of course with a result class to get the result and then the result will be of generic type T because we want to pass something with this result class what is the thing in case we succeed then we want to pass the data and in our case the data is going to be the products list and when we fail or there was an error then we want to pass a message what is the error so if there is no an connection or uh something is wrong with the API or anything then of course there would be an error and we want to pass a message for some error handling or exception handl or something then to tell the user uh there is something wrong to just tell them and we can also pass some data with the error in case for example when we fail loading the data from the API then we want to load it we want to load something that we already cached in the database for example then we want to pass that but yes this you get the idea that's why we need this result class so let's now create that data and message that we can pass so the data that is of course a generic type because it can change in our case this is this one but we can also pass something else for other apis if we use them that's why we make it of generic type to make it reusable and it is by default null why null because when we don't pass anything then why would it why wouldn't it be null and uh then the message so message is going to be of type string and it is by default null again so I made a typo here have three SES but uh while with this again be n in case we we succeed on loading the data then we might just want to pass the data we don't have an a message to pass so yes now inside here uh I'm going now to create the two cases there are other cases like is loading in case we are still loading or something but for the simplest I'm only going to create two cases the first one is going to be uh the sex the the success case so success uh and of course it is of generic type T and the Constructor of this class now we take the data T that is knowable and it will inherit from our result this one uh again and then we'll pass the data because we only want to pass the data now we duplicate this for the other one which is the error case and for this one we also want to pass the message not only the data so message of typ string and it won't be null because we want to send a message when we fail so now we want to pass the data and the message as I said the data in case we want to pass something else instead of when we get the error from the API yes this is now for our result class after that I'm going to create the interface to get to get uh the products so a new cink class file this is going to be product repository this should be an R but this is not a class it is an interface actually that will have one function which is a suspend function because it will access this one from our API that is also a suspend function and we'll call it get products list why am I creating this repository interface to to just uh depend on abstraction in case we want to use a different API or something then we can just change the implementation but the interface will stay the same for testing to make testing easier for us in case we want because when testing we're not actually going to use the interface I mean the API we're just going to create some fake API for that so this will return a flow uh not this flow but let just reimport it this one from uh uh cortines and that will return our results CL class of course and now the generic type is going to be a list of products for product like this and yes this is it now for our interface now let's create an implementation for that so inside my data package again I'm going to create an interface I mean an implementation but this will be just a class in this time and uh we need to uh pass now an instance of the API because that's how we can access of course the API so private V API and this will inherit from our repository product so product repository and now let's overwrite the function like this now inside here we can get the products by first we we need to return of course a flow just create space so what a flow is for those who don't know um it's just like a sequence of things that can happen for example as I said if we had on loading case in our result then the first thing we want to to admit to the flow is we we started loading and then when we get the data now here we get the data when we of course to get the data then we just finished and we now stopped we that we stop loading and yes so this is why a flow is really good for this these cases I will actually make a video about flows because I use them all the time in my apps and I think you should also use them if you don't because they so efficient and good for Io operations or like any other thing but mainly for this case I use them uh so we return a flow that is uh the result of our list of products and uh so we create a variable for that so while products from API that's what I'm going to call it prot from API and it is now try because we could get an exception so to catch the exceptions the first one could be an IO exception so IO exception we're going to to catch that and then the second one um that we may get is an HTTP exception we need to catch that as well so first of all let's just handle in case an exception of course first of all we need to print to see what happened and then we want to admit to the flow that we failed on loading the data so mm then uh of course the result that the error case that we created inside our result so result do error like this then we just send the message to that so let say error loading products for example you could have better like uh exception handling or something to actually tell the user what's wrong but for the simplity I'm just going to make like this and this is message not product we have an error here no value for data I mean this is data not message not [Music] data uh data needs to be null by default right here because I may not want to pass any data but as I said let's go here in case I want to pass something else here for example something from uh a database then we can pass that with the data right here and then when we fail we actually want to return the flow because there's nothing else to do because we just failed and the same for the second one like this error loading products when we have an HTTP exception and now but when there is no Pro uh when there is no error I mean what we are going to do inside our Tri block api. get products list so this will now execute which is a suspend function and in case something goes wrong then we'll catch the exceptions uh we might want to actually catch other exceptions like a general just general exception just actually copy this and paste it right here this will be just exception yes like this in case actually the exception is none of these types so this is what would happen if we have an exception so what we are doing is we want to get the products and in case something goes wrong then we just catch the exception here and after that after we do get actually the products and there is nothing wrong so this one is actually not null and we have the products and just we need to emit that with our flow so emit um outside the function so actually right here emit now uh result do success now because we success and then we pass the data that we want which is products from API which is this one do products because this products from API is actually uh let's put the cors on it so it's of typ products which is actually which has all those properties but we're only interested in this list of products that's why do products because that's what we want so actually uh this is it for our data package so this is how we can get uh the data from the API and this is so reusable so if you want to create a different API then you can still use this result class and in case you want a different API or something then you can just change the implementation and you wouldn't touch this repository neither you will touch uh like your view model where you get these and then show them in the the screen you only want to change that this implement because literally you can just remove this API from here and then change it with a database room database for example and it will literally just work the same so there wouldn't be any problem that's why I always say depend on on abstraction instead of just directly creating new stuff because that's not a good practice now after that I'm going to create my view model but first I need to create a presentation package so this is now my data package uh package now I'm going to create my presentation one to have my view model and Screen inside it but as I said screen will be just in my main activity so presentation package uh inside here we will have a view model of course so product view model and that uh needs to start with a capital letterer instead of small one or low case one and now we'll inherit from view model to make this of course A View model so view model this one under with X but keep in mind I'm not using any dependency injection here so uh yeah if I want to pass something to this Constructor I mean to to the Constructor of this view model then we need to create a view model Factory for that which is actually what I'm going to do because uh I need to have the the repository I need to pass the repository to call that to get the products but I'm not using dependency injection if I would use dependency injection this video will be a little too complex and yes that will handle like dagal will handle this for me but that will be too complex that's why I'm not going to do that so let's just create now my private VA uh product repository uh of course the uh interface not the implementation as I said I'm going to depend on on the interface and then the implementation can change in case I want to change it now after that inside my view model just create space the first thing we want is a mutable State flow of products so the products that we want to get from there so V products that is going to be a mutable I mean private V I did not write V so mutable State flow this one and the type is a list of product like this one and then the default value is going to be an empty list so it's empty by default and then let's create the public one that we will uh access from our screen so products oops products and uh it is products uh as state flow and after that a channel for showing a toast in case something goes wrong then we want to tell the UI to show a toast and we can just send that with a channel so private well actually haven't created any video about uh flows State flows and channels yet and I'm going to create a video because they are so important uh they make programming Android programming really easy and yes they're just so efficient and what what they meant to do so uh this is show toast error Channel show uh error toast Channel just this channel to send to to tell the UI or the screen to show a toast this is a [Music] channel of uh type Boolean so just will just be a bullion in this case in other ways we might have had that inside our result this one uh what is it I don't know but uh yes this one we might have had another case of is loading to to know what whether we are loading or not but just just create a channel for now you can then do that because it's the same principle watch show I'm just going to copy this name V show eror to that is show Eros channel. receive as flow so that's now how we can get flow from this and now inside my init block I'm going to get uh the data or the products so once we fire this view model then I'm going to get those and that will happen inside atin because those were suspend functions so view model scope do launch who for those who don't know what quines are because I did not you know my channel is new and I haven't created a video about cortines yet and I use them again all the time cortines basically to make uh synchronous task so we don't block the UI because we don't want to make those IO operations that take time uh inside our like with in our UI thread that will block the UI and they will be like l or glitch or whatever you want to call it we don't want that we want our app to be smooth that's why we we do those IO operations or things that just might take so much time uh inside coroutines so this is how we can create a view model scoped coroutine so creating inside a view model you could say and now we can use our product repository this one that was created to get the products list and now we got a flow of products that's why we want to collect the latest one and this will return the [Music] result result like this so the result of course is uh whether we have loaded or we failed on loading those so uh when oops result and we can use underw Studio to get uh the other remaining branches for us so when there is an error what we are going to do is we're going to show the toast error so show toast error dot send now to the UI true hey show the toast error that's literally what just this means sending a true and when we succeed on loading then we want to change now uh the our products state or so uh result do data that's how we can get now the data uh of course and then we just need to make sure that it's not alll this is how we know uh this is now whatever with executes in here inside this SL block that means this data isn't null so this will of course get the products list uh products like this products list is the same and then the our uh mutable state. update uh to the new one products I need an O here and uh yes this is it for our view models so we got we get the products and then we update our product State here and in case there is an error we just send uh through a channel to the screen hey we have an error show a tost a very simple View model and inside my main activity now which is the last thing we want to do but actually I forgot before our main activity we want to initialize uh retrofit so I'm going to create an object for that in case of course we use dependency injection then theal will do this for us but yes I'm just going not use inde dependency injections so I'm going to call it rrit instance so R RIT instance and it is an object what is that this [Music] one and inside here this is how we can initialize an instance of retrofit for our API the first thing we need is to create an HTTP login Interceptor and that is required by retr to to just log uh what we are doing or the API cost so private VAR inceptor uh not equal but that is an HTTP login Interceptor this one and it is equal to http login Interceptor do apply yes like this inter receptor and apply so we need to pass a value for the level and that is HTTP Interceptor I mean login Interceptor level body this is how we create that and now we want to create an OK HTP client private V client is uh of type okay HTTP client and it is go to okay http [Music] client. Builder to build that do add Interceptor and it is the one that we've created do build so now we have the client let's just create some space down here and after that we want to now create our API instance so V API API is of type our API that we've created and that is equal to retrofit so this is how now we can create the API so R retrofit do Builder do add the converter Factory so that converts that Json uh body to our data class so that's why we need that Json convertor factory. create so this Factory converts that. base URL which is the one that we've created inside our API uh api. base URL and then the client which is client and build oops not this but build do create now the API want that's what want to pass here class. Java so we just created an instance so I don't seem to need this an instance of API and I just initialized R instance so if I want to use a different API then I just create a different instance here can still use this but I just create for example a second API for another one if I'm using it but in my case I don't so yes this is how we creates that now after that I'm going to create my uh view model Factory to pass the API that I've created it because I don't use dependency injection in the factory is just defines how an instance will be created in this case how our view model is going to be created and then we want to tell that it's going to be the one that we've created here so private V view model and buy view models that is my product view models this is going to be a little too long little Cod but yeah I don't use any dependency injection that's why there's no other way to do it Factory producer we need that to produce the factory for us that is an object view model provider do fact fact this provides of course Factory and then override this create function uh that returns this super class but we don't want the super class instead we want our view model products view model and then we want to pass the repository but in this case we'll pass the implementation so products repository implementation this one and then the API because that wants the API so retrofit instance. API and then we just write as T and yes I've just created my view model Factory in I past the API to it or the product repository away and that I passed the apepi tool and after that I'm going to create now the UI which is uh the fun parts of this so inside my Surface I'm first getting I'm going to get the states the product list state is just one state so product list that is view model. products. collect as State this one do value because I don't want to call Value every time I need this so yes now we have uh our list and we got it from this state so whenever this state changes this will also change and our uh our UI will update now we want to show the toast in case there is an error right here uh to do that we need to do it inside a launch effect so launched launched effect uh to do this in a safe way and the key is going to be view model. show error to channel so like this whenever this changes this will fire and then we'll see whether we want to show a to or not so to get now the uh value from this view model Dosh channel. collect latest because we want the latest thing uh this will return aoan show or not we need a little arrow here aoan and we just check the value of the ban so if show then we want to show it then we want to create a toast do make text we need context and we can't create that inside there but in a composable in compos to create the context we just need context is equal to local context. curent that's how we can create the context and then we going to pass that and then uh the text is error I don't know just say error and uh toast do sh the length then do show to show that toast so now this is it for our toast now inside our lunch effect we want to see if we have items or not so if product list dot is empty then we don't have items but else we do and when we don't have items we just want to show a progress bar that is going to be inside a box fil Max size the modifier and then we want to say content alignment center to put the uh Pro ress bar or the circle actually the circle progress indicator inside I mean in the center of the box so circular progress indicator in case we don't have that in case the product list is empty but when it's not empty uh this will now execute inside here I will create a lazy common which is by the way the topic of my last video in case you don't know what lazy colon is for any reason you can check my last video and you will know what that is and how you in a deep explanations so this will take a modifier to of course fill the max size uh and then we want to Center horizontally our elements so horizontal alignment center to put them horizontally centered and the content padding so the padding between not between but from the like the pattern of the content itself that we're going to that we have inside here uh content padding is padding values 16. DP import DP and now inside our lazy scope we need items because we don't actually need index for this that's why I'm not going to use the other one which is a item for index or something but this is enough now I'm going to create now inside here the product I'm just going to call the product I will create it and this will take now the product to display its data so product list I or it because this returns index just see what that is this Returns the index in which we are so index uh after that we need to create a little bit of space so if we check the app a little bit of space between each product so using a spacer height 16. DP now I'm going to create this one actually outside outside here uh composable fun product that will take a product like this and of course we have images here so we'll see how we can use Quil which is the library that I have a dependency of to load those images and show them as I said Quil is the equivalent to uh Glide if you used XML before and we don't have Glide in j p compos we have quiz so uh in qu we have an image state that tells us whether we have an image or not so the state of the image and inside our state we have the image itself so image state that is remember uh assign image painter and the model let's just go to a new line for this the model will be I mean will be image uh request. Builder and then we need context so local context cent. data now data will be our image URL and then our case let's go to the API and it is this thumbnail what is it what is it this is one the one that we show we could show different ones but that's what I want the image thumbnail product. uh thumbnail this one and uh the size is going to be size. original from Quil of course and then do build to build that so now we have an image state but actually do state to get the state out of that so State now we have an image state that we can check whether we have an image or not yet and of course get the image out of this state now what we need to do uh want to create a common because we have a colum here holds an image this text and this other text so colum uh that when we need a modifier uh we'll clip that so clip round Corner shape let say t.p to make it kind of beautiful and then the height of this outside here actually dot height is going to be 300. DP and then fill the max width and then the background background is going to be material theme do color scheme do primary container [Music] inside our column we now check the image state so F image State as aign image painter do state. error so in case there is an error then we do something and just copy this and paste it in case there isn't an error so success not is actually any May me not as here we need ease so in case there is an error then again I'm just going to show you know this progress indicator again that will still load in an image uh but I won't feel the max size or just fil Max size the same thing fil Max size but at yeah this will also take the space of the uh text so just fill Max width actually and the height uh height will be 200. DP I think this is better and we have our Circ indicator but when we have an image now we want to create an image instance I mean an image composable now let's create that image and the painter is going to be image state. painter uh let me just format this the content description is product. title now we need a modifier in in our image modifier to give it the size or fill I guess I need modifier fill uh width fill Max width and then the height is going to be 200. DP so yes this is it actually for the image we just need one thing which is the content scale would be crop so to crop the image in case it doesn't fit exactly the size we given it then uh below this image in fact below this all of this that handles the image we need a spacer to have a little bit of space between uh the image and the text. DP so six. DP and then we need to create a text to show the title and the price so text the text is going to be the product the title and then the price so just like this you say price is [Music] now uh product dot price uh so I guess I'm just also going to add a dollar sign here here now this is it for the text uh but this we need a modifier to give it some padding let me just format [Music] this a modifier to have padding horizontal padding why horizontal padding to 16. DP because we just want to have padding from the start and the end here 16 DP what if else let me just take this modifier to the top what else do I need is the font width to make this uh let's say font size first do 17. import SP and font weight will be Su bold because it is a title we want to copy these two because we want one them for the other one and down here actually you want to have another space spacer let's say 8. DP or actually let's just not have any spacer there the text for this one is going to be just product title I mean not description and it will be smaller than this so let's say 30 SP and it won't have this uh big text like that so I think actually this is it for the UI in and this is it for the entire app there's one last thing which is the internet permission because we need internet for this so internet I mean user permission internet now let's close this one and just run our app and hope for the best the app is running and we do have the products the images and everything is working fine now let's see the other cases I've covered let's say I don't have an internet connection so let's uh let's turn on airplane mode it will show an error toest as you can see and it will keep loading but it won't actually load that after I get internet connection because I didn't handle that but in case now the image URL isn't working or there is something wrong with the image image so let's go to the image what is it what is it this is the title I mean URL in case there is something wrong will we actually get that progress indicator or not soet so yes when there is no image or when it's still loading or with is slow internet connection then that's how it's going to look like uh now this is the final app we have a list of products that we use retrofit to get so this is our retrofit video tutorial thanks for watching like this video if you find it helpful subscribe and leave a comment if you have any question and see you in another video bye
Info
Channel: Ahmed Guedmioui
Views: 14,719
Rating: undefined out of 5
Keywords: android studio tutorial for beginners, android studio project, android studio app development, android studio app, android studio app project, kotlin android tutorial, kotlin tutorial, kotlin multiplatform, kotlin full course, jetpack compose tutorial, jetpack compose android, jetpack compose mvvm, jetpack compose state, jetpack compose viewmodel, jetpack compose vs xml, jetpack compose app, api key, jetpack compose animation
Id: 8IhNq0ng-wk
Channel Id: undefined
Length: 53min 37sec (3217 seconds)
Published: Thu Nov 23 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.