Image Caching with Coil Compose - Everything You Need to Know

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys and welcome back to a new video in this video I want to give you a full guide on image caching in Android using coil and Jetpack compose being able to confidently use such an image caching Library like coil is really essential as an Android developer out there because let's think about it whenever you have some kind of image URL in your app like I prepared you for example and you want to display that image in your app what you need to do is effectively and HTTP request so you make the request to the server hey I want that image data the server answers with the image bite and such an image is typically larger than a normal HTTP request which just answers with Jason and if you now have a list of images for example a list of URLs you want to display these and typically such lists are implemented in a lazy manner so that new entry show up as you scroll then whenever you scroll a new image and a new HTP request is fired off to fetch an image that is of course terrible terrible performance so we need some kind of solution for this and the solution is called image catching so the first time we actually load such an image we need to save that persistently on our device but typically we don't want to keep these images on our device like in our Gallery no we just want to cat them we want to save them temporarily just that in in case we need them later we can quickly fetch them again without needing to make a network request and because doing something like that is actually a very complicated progress in system there are these image caching libraries which make this in ease however there is still a bit to learn about these especially about coil that is what we typically use on Jetpack composed to to do this to use image caching and that is what I want to cover in this video so please just make sure that you have an empty Android Studio jetpack composed product and you've included this coil dependency so coil KT coil compost 2.4.0 synchronize everything and in main activity make sure you have some kind of image URL you don't need to use exactly the same one as I do just some kind of image URL so in Google Chrome just right click on an image copy URL of that image and paste it here in studio and then we can get started so if it's really just about displaying an image with coil we have this async image composable this async image composable has tons of parameters we could pass the most important one is the first one which is the model and the model could be anything um can't really be anything but it uses the any type because coil really supports tons of different formats for images in our case that's just the image URL but any type of image format is typically supported here with coil so you could also pass in a bit map you could pass in a Content yri you might also be able to pass in a b array if that's an image I'm not too sure about that but might also work and the second mandatory parameter is the content description just like for the normal image composable as well and it's very important that we assign a size of that image so that we actually see something and we can do this with a modifier fil Max width and we then want to give it an aspect ratio of the actual image Dimensions so aspect ratio and the ratio is in my case 1 1,280 F divided by 847 F so this is the images width this is the imagees height and if we divide the width by the height we get the aspect ratio and if we launch this then we should now already see um that actually nothing works because we need to add the internet permission in our manifest that's something we love to forget so in manifest users permission internet and then we should see this build still crashing but the next one should then work yes that one crashed and here we can relaunch this this one should hopefully not crash anymore and we don't see an image how comes let's take a look Okay the reason was just because I pasted the wrong image uh so you probably saw your image if you copied it before if I relaunch this and take a look here then I also see the image you can see a little bit of delay since it of course needs to be fetched from the network after it can be shown but what did coil now do because it didn't simply make the network request it also did something behind the scenes and that is caching the image because if we go up here and we turn on airplane mode so we are not connected to the internet anymore and we relaunch the app then we can still see the image and that is because the image is cached on the disk and when using coil there are two types of caches we are dealing with on the one hand as I said the dis cache and the memory cache the memory cache just keeps the image on the devices Ram so nothing is really safe persistent but that also means that across app relaunches you can re access the image because the RAM for a specific app is cleared when it's uh when it exits on the other hand accessing the ram is much faster than accessing the dis and really loading something from the file system but as you just saw we relaunched the app and we can still see the image which clearly indicates that this was cached on the dis and in general the default behavior of coil is actually a mix between in memory caching and dis caching So Co will take a look at the image and if it has a certain size and dimensions then it will better cat that on the disk to not occupy too much RAM if it's a smaller image then it will use in memory caching however we can completely configure this way of caching as we like so let's see how we can do this to execute such a request to load an image coil uses so-called image loaders so the image loader not only loads and fetches the image from the URL no it will also handle all the caching behind it and there is already a Singleton image loader wherever we have access to the context so here in an activity we of course do have access to the context and therefore we can also refer to the so-called image loader which comes from coil that would now just refer to the default image loader which is a Singleton but we can change that default image loader for um for cross our app and we can do this with an application class so in our root package we can create something like my application make that a class which inherits from application and if in here we now overwrite the um New oh actually we also need to implement an interface which is the image loader Factory if we now override the new image loader function this is the function where we can create our very own image loader with our own image loading configuration with our own caching configuration which coil will use for all composable and we can do this by returning an image loader pass in the application context so this and then we say new Builder and then we can configure this here with a bunch of functions okay let's call build and then configure it in between on the one hand we do have a memory cache and a memory cache policy here we can say for example that we are using a cache policy of enabled disabled read only or write only enabled should be pretty clear that means we want to use the memory cache we want to cache in the devices Ram disabled also pretty easy to understand that means we we're not using the memory cache at all read only means we only want to read from the memory cache and write only means we only want to save images on the memory cache um but not read from it the last two here don't really make sense for our Singleton image loader um that only makes sense if you use different image loaders for different image composes since if your whole memory cache is read only then it doesn't make sense because you don't have the option to write something in that cache but if one composable actually has the um right only image cache for example the other composable has a different image loader with read only then that works but that sounds like a very very special use case to me so we're just going to use enabled here and then we also want to use our very own memory cache which we can Define here in this Lambda by using memory cache. Builder and in here we need to pass in the context so this again and then we can say Max size bytes Max size percent so how big our cach is for example I don't know 10% of the remaining Ram that would be 0.1 we could also enable weak references and strong references strong references are basically um images that would not be garbage collected if we want that we need to set true and weak references would be images that could be garbage collected um which we could also allow here I just leave the strong references enabled here and build and then we effectively used a different cache or rather a different cache configuration we still need to go to the Manifest and use Android name and uh set that to our application class but other than that we now configured our cache individually let's also do the same for the dis cache so disc cache policy that's another cache that's on the device like the the persistent cache and here we can use one of these policies as well um that's called enabled and then we have a dis cache Lambda where we can create a dis cach cash. Builder this cach Builder here we don't need the context we can directly call Max size percent that would in this case be the remaining space that is left on the device so um for example 0.3 that means the this cash will use up to 3% of the remaining disk space to cach images that was very important if you configure you very ear this cache that you assign a directory because that's not done by default and here the directory where you want to catch these images is typically just your cach directory that already exists so we can just say cash directory and what else do we have here clean up dispatcher so you can sign a ctin dispatcher when the cache cleanup is done um yeah file system you have a lot of options to configure this here with what we specified we should be fine and this should not be a float but rather that double and let's see what else can we configure here this cache policy memory cache this cache memory cache so just some image specific configuration so if you're loading a bit map you can add a bitmap config some color configuration um Hardware acceleration I'm assuming then the orientation of the images when you have a bit map call Factory is very interesting so that's basically a Lambda that allows you to intercept the requests coil will make so let's assume you want to access an image which requires authentication so you just need to attach some form of token or so to get that image then that would need to be done as a header for that HTTP request and by default Co doesn't know that but with this call Factory you can make sure that you add this token on the header of that request so here you just need to return a call Factory I don't know how that works um call. Factory call from OK hgp I guess call. Factory and in here yes you get that request object which you can then map to a call so it. new builder for example you could say you want to add a header authorization or and then add your token in that header we're not going to need this here just that you know this exists what is definitely very useful is to assign a logger since sometimes it accidentally happens that your cach misbehaves and uh maybe your hash always fetches the images from the network but you're not even noticing that which later on causes performance issues you can find that out with a logger explicitly with a debug logger which you can attach here I would say um before we move on with further configuration we try this out what we what we did so far by going to our main activity and relaunching the app taking a look at logat because we added our logger this will now give us a little bit of clarification if about what our app is doing and you can see it actually failed um so fetching the image failed that is definitely uh very useful you also won't see anything here I'm not sure why it failed no address associated with oh because I of course went into into uh airplane mode then it of course makes sense let's disable that again so if we relaunch this then take a look here now it was successful you can see network so it fetched the image from the network but if we now rotate the device for example then it should not fetch that again from the network but rather from the disc cache so I rotate it you can see take a look at locket this time it's successful and it loaded it from the dis so this is how you can see in coil where images are loaded from which is typically very useful if you scroll down you can actually see that it now loaded the image from the memory cache because I wrote it at the the device again so Co has some kind of internal strategy by default to um decide where it's the smartest to load an image from maybe if the device is uh short on memory resources it might load it from the disk if it's not then it might loaded from the memory as you can see so call is pretty smart a pretty smart library and in most cases you are already fine with this but what if you want more control over the cach what if you maybe want to clear the cache that's something you might want to commonly do for example you have a social media app the user can log in and then you fetch a bunch of social media posts a bunch of profile pictures and you cach all these so you don't need to fetch these every single time the user Scrolls but if the user then logs out you don't really want to keep all these images in your cache and make them occupy memory in that case you would want to completely clear the cache and how do you do that well let's take a look at that we have a column here so we want to add a button and when we click that button we want to clear the cachee import column here modifier is modifier. filmx size and we want to put in the image in our column and Below let's just have a little bit of spacing so a spacer with modifier. height 16. DP Alt Enter to import DP and then we're going to have a button and when we click this button we want to clear our cache and the button text should say I don't know um clear cache for example when we click this how do we now clear the cache for that we need to use our image loader and since we are in activity we have access to that if you don't uh if you are not in an activity then you need to um inject the context wherever you are and then you can say context. image loader but we can pretty much say image loader that this cache. clear and the same for our memory cache image loader. memory cache. clear and what is the warning we get here um oh okay it's experimental let's add that to oncreate but if we now do this and relaunch our app and also take a look in lock cat then you can see now it loaded that image from the dis as you can see down below if we now hit clear cache and we rotate the device we expect it to be loaded from the network again because we cleared the cache let's rotate let's scroll down yes you can see now it is loaded from the network again so clearing the cash works fine but now this clear the entire cach what if you only want to clear one or some amount of images maybe you have a list of images in your app and you only want to clear the images which are displayed in that list but not all images in your app then coil luckily also allows you to do that in that case we don't want to call clear but rather remove and we need to pass in a specific key so the way coil Works internally is it Associates an image with a key that key must be unique and that key must refer or must point to the image that it stands for with URLs that is pretty cool because the URL itself is unique so whenever you make an a request or whenever you have an async image with a specific image U code will take a look at its internal cache and see if it already has a key with that URL and if so it will load the image under that key from the dis or the memory and if not it will fetch the image from the network and then save it internally um with the Yeah by using the image URL as the key and that way we can also just call this cach remove with the image URL and then we're only going to remove this single cach image if we would have multiple images multiple image URLs which we would display here then these would not be affected the same works for the memory cache here a little bit differently and here we need to pass in the memory cache key memory cache. key but here we also just pass in the string so just our image URL and if we're then go up and maybe duplicate the image URL image URL 2 I paste in another image URL here so there's no difference image and let's say we then have two async images another one here the second aspect ratio is AIT different for mine um this one is 692 F but of course use whatever Dimensions your image has and we only now remove the first image from the cache so we don't say image url2 here only image URL one what will happen is if we rotate the device back and then we launch it take a look in lock cat then uh it actually loaded the one image twice oh because I didn't assign the image url2 here so let's uh relaunch this again take a look here in lock cat okay now the first image was loaded from the disk which is what we expected was still on the dis cache the second one which was new was loaded from the network and if you now take a look in the app then here are two images and when I click clear cache we should only remove the first one from the cache so if we remove this we rotate our device then we expect that only the first one is loaded from the network again but not the second one so let's do this clear cache rotate the device and take a look what happens here yes the first one um no this actually the second one since it was loaded faster was loaded from the dis and the first one was fetched from the network again so this is really how this key image mechanism is working with coil and how you have that really fine grain control over what to remove from your cache and that's really the core what you need to know about image caching on Android there's one more thing which might be interesting but it's not directly related to image caching if we take a look there's also a subcomposition a circular progress indicator when uh we actually when the image is fetched that we show a progress bar in that case so that's also covered by coil um but that is not directly related to caching just something cool uh I thought I would have mention and if you enjoyed this video and also enjoy J compose then you definitely don't want to make the 20 deadly mistakes that I've summarized in free PDF for you you can get this PDF as I said completely for free down below by clicking the link so you can really prevent these M tags that will backfire much later maybe your users will complain get really nice code examples and explanations why these are mistakes how we can fix these and so on all package into a free pdf so get it below other than that thanks so much for watching this video I will see you back in the next one [Music] bye-bye
Info
Channel: Philipp Lackner
Views: 11,590
Rating: undefined out of 5
Keywords:
Id: qQVCtkg-O7w
Channel Id: undefined
Length: 21min 27sec (1287 seconds)
Published: Sun Oct 15 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.