 Hello. Yeah. Hi, everyone. I'm Garima from ThoughtWorks. And I'm an application developer over there. I worked on Android for a couple of months. We have built an internal ThoughtWorks app. Apart from that, I am a DevOps person, service management, et cetera. So quickly coming on to today's discussion. First, let me cover what I'm going to talk about is performance bottlenecks and why that is the other side of usability. The sections that I'm going to cover are, I'll talk a bit upon usability and performance, why they both overlap each other in case of Android. Then I'll talk more about performance bottlenecks that we have faced in our previous apps and how did we go about solving them. And then at the end, I'll talk about how you can gather more and more feedbacks from user about performance bottlenecks. So to start with, before I start, I want to tell you guys that this session is going to be pretty interactive. I would like to have as much inputs from your side as possible. So let's start. I would ask you the question, what is usability? What do you think by usability? Come on, if anyone can answer that. Exactly. How easy it is to use. How swift the navigation is. When we come to Android apps, how swift the navigation is. How intuitive is the app? How beautifully the app launches. As a user, how good I feel when I open the app. Now tell me, after usability, what do you feel about performance? What is performance in Android? Exactly. And why is that that important? Because the way in which you use mobile is only for some seconds. If the app is not working, you exactly come out, even though it has so great usability, great UI and all. Exactly. At the end, that is adding towards the user experience. So in case of Android, especially when we talk about performance, concurrency, scalability, and those things get eliminated. So in case of Android, we can clearly say that usability and performance overlaps each other. When we talk about usability and performance, we come up with these buzzwords. User experience, user-friendly, stylish, designed, heavily featured, swift navigations, everything. Now let's talk about a few broader points. The app should be quick, as you said. That is the basic need that I require from my app. The app should be quick. Let's take an example of Gmail. You launch the app, there is something. There is no loader coming up, and there is something which is already present in your app, which Gmail has already downloaded, and that has shown. Next comes engaging. The best example of engaging app is Angry Birds. When I start using it, I want to go on and on. I want to clear as many stages as I want. Next comes intuitive. These all words are very tightly coupled with each other. When we talk about intuitive, if I want to add some data, if I want to add something else to my app, there should be a plus button. If I want to search something, that magnifying glass should be visible. These things adds to intuitiveness. Error handling, yes. If there is no internet working, your app may crash saying, oh, something happened. Please, do you want to reopen the app? Next comes easy to learn, as the name suggested. WhatsApp, I installed it, and I just went on using it. It was really very easy. Next comes effective. Now, by the term effective, what I mean is user gets all those features that he's expecting from your app in that app. For example, let's take the case of Instagram. It gives you all the functionalities that you can do with your image. Gives you built-in templates to redesigning to your image. It will give you focus and everything. So that is the best example of effectiveness. And last comes well-styled. With well-styled, I mean two things. First is good-looking. Yes, obviously, we want a good-looking app. Second thing which comes is how consistent is your app? Consistency in terms of different apps as well as a single app. Your single app should be consistent with the successive layouts. Your first layout say orange color, and second layout is a purple color. Would you like it? No, there should be a consistency. So we have talked about these things. Now, let's talk about the performance bottlenecks and what is the key focus of this session. Now, think of an app which is very beautiful. You open it and you feel, wow, what an app. And as soon as you click on the second button, it hangs. Nothing is happening. As a user, how will you feel? In the next step, for the second step, you went to another button, and again, the app crashes. After some time, you will uninstall it. We don't want those things in our app. So as a developer, what we should do? What things we should keep in our mind while developing the app? Not as a UI person, not as a UX person, that this should be the design, this should be the buttons. Here it should be in that. No, before that, you need to think as a developer that what changes, what tricks that I should keep in my mind will add to the performance. So that's what I'm going to talk about today. I'll share my experiences that we have faced. These were the problems that we have faced and how did we go about solving them. So what are we going to do is these couple of steps that we are going to follow for some basic version of app. So I have this shopping application app, very basic version of it. It has a couple of performance bottlenecks. As an audience, as a user, you will have to tell me what are the problems that you see in those apps. In the next version of it, we'll remove those apps. We'll touch a technical bit of it that how did we go about solving it. And then we'll see the next version. And again, in the next version, we all will come up with the problems that we are facing. We'll remove it. And that's how we'll go take our basic application to a pretty nice looking application which you can actually take to Play Store. So this is what we are going to do. So before I start off with the first demo, this is what our basic application is doing. As soon as user launches the app, there is this great view. The app makes a server call for the list of watches. In case of shopping application, I have used watches. Now that list of watches is stored in DB. As a next step, the watch comes with these four things to it. First one is name, description, thumbnail URL and image URL. It's not actually the image, it's URL. So whenever user clicks on the app, it fetches these things, stores in DB and gives a name and the thumbnail URL on the grid view. When I click on one of the watches, I am taken to the next layout which has name, description and the image. Image actually gets downloaded. So let's see the first version of our app. This is the shopping application app. I launched it. I launched it. Hopefully the internet is working fine. What are you thinking as a user? What do you think? What is the problem with this? I'm using main thread to load the application. Exactly. As a developer. Yeah, the internet is working actually very slow. Do something. Yeah, we are working. The app is not loading. As per my expectation, it should have get loaded by this time. It is taking a lot more than expected. But yeah, this was my main intention. That app, as soon as you open your app, this is the first feedback that you get. The waiting period was too much. As a user, I was confused that even the app is working fine or not, whether there was no immediate feedback. And at that point itself, you lose your first user. You, the user don't know whether it's working fine. Should I go back? What should I do? Have I done something wrong? Is my phone itself got hanged? And you know, user can say, oh, this application actually hangs my phone. So these are the aspects that you should think about when the user launches the app itself. So now let's try to locate it with what is actually happening in the background. What is happening is I make a server call for list. I store that in DB, the second image. I make a server call for images. And then I combine those images with a list. Until that point, I get this black screen. And at the end, I get the products with images. The problem is over here, right? Now, as a developer, you tell me, what can we do? Separate threads, show a notification, saying that it is loading. Don't load everything at one time. Exactly. So let's take his first thing that he said that instead of this blank screen, at least give a loader to user that something is happening, right? So let's see the solution to it. What did we do? Yeah, instead of calling your server call directly in the main thread, use async task. And yes, progress dialog, start your progress dialog when you give a call to async call, async task. And then async task comes with a callback functionality. You can use this callback to dismiss this dialog. Technically, how can we go about it, right? Now, let's see the second version of our app. Yeah, see, it worked in the background at least. Before that, I will quickly remove one of the dev settings that have done. So I'll remove the first version and install the second version of our app. And user gets a loader. Now, what are you thinking? What is wrong with this part? User gets a feedback, right? Still, there is some problem. Sorry. So the user can't do anything till the loading is not finished. Yes, exactly. Couple of feedbacks. This loader is going like infinity. So as we saw in the timeline that we download the list and then we download the images. Images are actually the thumbnails, right? So instead of, yeah, this is the version two. The problem that we are facing is the loader is going on and on and on. The waiting period is too much. Now, trying to relate it with what is actually happening. User makes a call for list, stores and DB. Server call for images. This is the point where we can change it. This part can be actually replaced with the actual content without images, right? But how do we do that? Any idea? Lazy loading placeholder. Now let's see what I have done, what we did, was to having two different async tasks. First one was a download images task without a callback. So as soon as you get your images in the background, they'll start getting populated. And this resource downloader, this callback doesn't wait for the downloading images to come. So that's it. Your problem gets solved. Let's see the third version of app. Anyone having any issues with any idea that what we did? Okay, so let's see the third version of our app. The internet is not working. So third version of our app. Hopefully this time it doesn't take that much of time to load. Yeah, I'm sorry. Yeah, the solution for the third version. Yeah, but we don't know the problem of third version yet. Yeah, sure. I'll go back to the previous slide, this one. You want me to explain? Point here. Yeah, cool. Let's see whether the app worked or not and it is not working. So let me change the internet setting for one. Give me just one minute. So till the time this internet start working, I'll take you through how, yeah, this page is at least there. So in this next case, yeah, this is the version in which the images are downloaded at the background and we'll see that the page, the layout first gets populated with just the list and then we get the images. This is also not working well. Internet. Okay, so till the time it comes over here, I'll tell you what the next problems that we face. Every time, even if the, when we scroll up and down, if you might have noticed, the images get downloaded in the background, right? If you scroll up, what happens is, Android's layout, the way Android's grid view and the list view works is, as you scroll up, the layout goes up and the fields are reused and with the populated with the next content, right? So every time you scroll up and down, the images, the thumbnails are downloaded, right? So the scrolling bit becomes little laggy. It takes time to scroll up and down and the images takes times to come out. So what can be the solution that you think of? Caching. Exactly, we can enable caching, but how can we do that is by, let's see, shared preferences, most of us might have used it. So this was the problem with the third version. We scroll up and down, the images are every time loaded and every time the images are downloaded, time is required. So this is what is happening in the background. When you scroll, images products comes without images. The solution is we enable caching. So I have used shared preferences. I'm sure you might know that there are some other ways also in which we can get images for our app, any idea. Downloading the images actually and storing it in internal device, internal memory, external memory, maybe use your database. Now the question is why did we go with shared preferences? Anybody having any idea why we should use shared preferences and in which scenarios we should use shared preferences? Yeah, as a bitmap, right? Yeah. So the user tickets, right, you know, whenever the application, JVM closes, all the incidents will be closed. So when the new JVM is created, I have to get the user tickets. So these kind of information will be stored that shared preference. Exactly, so the idea behind using shared preferences is when your size of data is small. So in this case, thumbnails images were really very small. I would not suggest anyone to use shared preferences, especially for images, but in this case it was thumbnail. So we went ahead with using it. The second point which added to this was the frequency of those images getting downloaded, right? You are scrolling up and down. So in that case, images will be required frequently. As a user, I'll just scroll up and the scroll should go on and on and on and if images are not coming, I would feel what is happening. Also, not to use internal devices, internal device memory was because every time you scroll up and down, at least there will be time required to get images from your internal memory. If it isn't shared preferences, it is there very closely with your app content. So the next version was actually without using our app with shared preferences and having caching. Let's see if the internet is working now, which I'm not sure. It's not working. This time I actually wanted the app to be present so that I can get more feedbacks from you. Let's see in how much time it loads. Till the time we can discuss about, what else? Async tasks, how did we go about using them? Maybe callbacks, when to use callbacks, when not to use callbacks. In our first version, we used just one async task. In the first version, the basic one, we made the server call directly from the main thread. The main thread was blocked. In the second version, what we did was, we called the async task for both of them to get the list as well as the images and then get back to the main thread. It's not working. And at the end, yeah, with caching and with downloading images in the background, we used shared preferences. Till this point, as a developer, we are satisfied. Now something is there which comes as a user experience. So as a backer of it, I have a screenshot taken of my app. So let me quickly get it for you. So this is the recording that I'm playing. And this is the version that I wanted to show you for the caching part of it that whenever user scrolls up, these three, this grid view will be reused to display the next images, next content, hence it will go up. And the content for these, this one which went up will get deleted. So in order to keep it with us, we used caching. Now there is some problem with this version also. Can anybody tell me? Something from user point of view, user experience point of view. Yeah, so we used caching for that. So now it is getting really easily fetched. Now don't think of as a developer. Now think of as a user. First time you open this app, you see a loader, you see content like this, but still there is something missing. Do you? Yeah, I actually didn't like the looks. And here comes a very basic requirement from an app. It's looks. We pay a lot of attention for looks, but still we forget that it should be consistent, right? If I go to go inside one of them, there is a red color which gets displayed. Yeah, this one and I go to one of them. And this is the content that I see. There is a very high problem of consistency. Previously in the first page I get to see purple color. And then in the next I see a red color and you know images are looking ugly. To solve this problem we can, you know, we can every time go and change our, change our layouts, the color that we are using. But for how many times are you going to do? You create one more layout. Are you going to design its layout from the scratch? That you know, if the text box is this, text box is this way, you change the color to purple, you change the action by or to something. Are you going to do every time? No, let's make it little agile. Let's introduce themes. Android itself gives you an option of using themes. But what if I don't like to use the normal pattern? Then we'll extend our themes. We'll, you know, we'll make tweaks in our themes so that the problem of inconsistency goes away and there is a fresh look given to my app. Now let's see how I have used inconsistency. So here is the way you can use themes in your manifest. You just introduce a style app theme and in style.xml you gave, so this is the reference that I have given and parent is Android Holo. You can always tweak your themes to, you know, give a new look to Android themes. So now let's see the next version of our app. Let me go and uninstall it. Now, this is the version which has a new theme and, you know, I have tweaked the Android themes for it. Let's launch it and you can see a... So if you have noticed, I just changed that Android manifest and the style.xml, but the appearance is completely different. Is there anyone who has used themes previously in their apps? Yeah, couple of you, but it's a really nice thing to use. It gives a drastic difference in the user experience. Just tweak it a little bit. It will give you really nice performance, not performance, but the user experience. Yeah, I'll take you to the code then. This is how we did it for our action bar. Just for the action bar, I said use this color as the background, which is orange. So as you can see over here, this orange color, it comes from the tweak that I have done to my theme and rest of them is all Android theme, which gets populated. Yeah, coming back to the presentation. Now we saw we are about to see the fifth version of our app, which is not coming that easily because of internet, but what else do you think, what else can be problem with the next version of our app? We removed the loader problem. Let me take you to test. This is how the app looks. This is the backup that I'm using from the screenshot. I'm sorry that the internet is not working properly, but this is the current state of our app. Now as a user, you are not able to identify what the problem is, right? So let's use some developer options. What I'm going to do next is, I'll go to developer options. This you can do in your phone right now itself that go to developer options. Enable GPU rendering. How many of you knows just want to check? Yeah, couple of us, but let's go over here. So I went to developer options and will enable GPU rendering. What it does it, it will display the content in a different color. Blue, green, light red, and red. What it means is on your layout, now let's, this is the screen that you see. Now let's break it into layers. You see different layers over it. Every time there is a layer on the pixel that overdraw is done, right? Every time there is a new layer, the pixel gets drawn. For one X and two X, that means for one time or two time, it's okay. Three time is fine. But when it comes to four or five, it's not desirable. Why? Because Android itself will take time to render, to draw it on the layout. And that time is not noticeable by normalize. Then why to not have layers? It's because you'll feel it when you go back and forth in your app. You can feel that there is a rendering time which is required. Every time you go, you go immediately back and forth. As a user, I'll go, oh, I need like this watch. I'll go, come back. I'll scroll, I'll go to the next. And that rendering time will irritate the user, right? So what is actually happening in background is this, I'll go to presentation now. We use the developer options more properly and we see this. The rendering time is more. Now Android provides you a very nice option of hierarchy viewer. You use GPU rendering, enable GPU rendering to know that on layout, how many times, how many times the drawing is done, red, green and everything. But you don't know which layer is actually doing that, which is the redundant layer that I can remove for that. Android provides you a developer tool in your DDMS. If you go and click, I'll quickly take you to that tool also, this one. On your DDMS, you can select your application. Go to hierarchy viewer, since there is nothing on my application right now, it won't show up. But generally it looks like this. It will give you the layers which are present and there are three dots connected to it at every layer. So consider that your layout had a basic linear layout inside which it had a image view and a linear layout. In that linear layout, we had two text views. This is something that is shown, right? But what do I get out of it? How do I know what is the problem, where actually the machine, the device is taking time to render is these three dots. Green means relatively, the time taken relatively was less, it was okay, okay. Yellow shows the relative time was 50% more and red is the sign that okay. On this layout, while rendering this layout, drawing it on the screen, Android took time. Now there are three dots. These three dots means, first one is the layout, second one is, I don't remember it well, yeah, draw and the third one is the actual, I'm sorry, I got confused, the first one is rendering, second one is layout and third one is draw. The third one is the one which is more, you know, which I focus more upon is because the time, the draw, actual draw time is over there. If that is red, which means that on that layout, on that specific layout, I want to make some changes, I would like to remove some content out of it. So this solves our problem and in the next version, your rendering will be much faster if you go back and forth. If the internet might have worked properly, I would have shown it on the actual APK that I have used, that yeah, the ongoing back and forth, it works fine. So let's see the app progress that we saw from version one to six is this. This was the first one, ugly looking app and the second one. This is actually you can take to Play Store, right? It's pretty decent, not a high five, but there are some couple of things that you can do next to it, you know, provide offline support, you can, you know, provide, every time user launches, they have no need to show the loader, the way Gmail works, right? The previously loaded content is shown and Gmail does the downloading in the background. All such functionalities you can do step by step, but this is the basic version with which you can actually launch your app. So our apps need to be agile enough so that the new functionalities, new features comes, we can involve them as easily as possible. Now let's see what is the summary, what we actually did. The problems that we faced were a black screen as soon as we launched the app, we added a progress dialogue. The waiting period was too much, we did the downloading in the background. Now the images were getting downloaded every time, then we used caching. In consistency, we used themes, we tweaked those themes according to our requirement and at the end there was a layout overdraw. This was not visible by the user, but what we did was to use developer tools properly, using hierarchy viewer, we could identify that there is some problem and then we removed this. I think optimizing layout was covered by Sriram in the morning session, so I'm not covering that. And at the end, other ways to get the user feedback. And why am I focusing on that is because at the end of the day when you launch your app, it's the user who's going to give you feedback. But before launching, before that, what you can do is couple of testings, like hallway usability testing. As the name suggested, go in your office, whosoever comes next in your hallway, catch hold of him, show him your app and deeply analyze his behavior, his spatial expressions, how he is feeling when he navigates from one layout to other, when he's trying to search for something. If you deeply analyze his expressions, you'll come to know that, oh, there is some problem over here. Next comes competitor analysis. Go to Blaster, look at your competitor, what they have done. Is there something really good which I cannot compete with? Try to do similar. Try to come up with new idea around it. Next comes dog-fooding. How many of you know what does this word mean? Yeah, exactly. Eating the food that you're going to give to your dog, which means use your app first. Be the first user of your app. For example, for this shopping application app, be the first one to go and purchase a watch from there. Not an expensive one, at least. But yeah, be the first user of your app. And at the end, yes, user comments when you go after you launch your app, go through the user comments and you'll come to know. Before I end up this session, I want to tell a few more things. While developing the app, we don't know what problems are going to come. What bottlenecks are we going to face? It's our responsibility that we design. We architect our app in such a way that even if some bottlenecks are there, we are able to remove them. And there comes the idea of using object-oriented programming, modeling your data models, using MVP or model view controller. Many of us know about these things, but how are we using them? Using single responsibility principle, keeping our app agile enough to, if in the future, even if a new functionality or a performance bottleneck comes, we can solve them in a quick way. That's it. Thank you. Questions, anyone? So why are you storing each and every thumbnail in the shared preference? Basically, when your app launches, all the shared preferences get loaded in the map, right? So let's say there are 100 thumbnails. So in that case, your app performance will be even worse. Yeah, yeah. So there is when your decision comes in that what you want to use, what is your use case? If you have 10 images which are going to come up, if you have 20, it's okay. And it's the thumbnail. If it is actually an image, a big size, it has a bigger size, then you should think of other options. At the end, you have to decide that if I can use a shared preferences, how it is going to perform. And if it is not, if you said 100 of them, then obviously go ahead with the internal memory, store it beforehand. Okay. Actually, if it's not a thumbnail image, it told that we can go for some other option. But taking internal memory, it again makes the app, makes use of the memory a lot. Is there any other option other than internal memory, external? External storage, right? As WhatsApp does, right? Sorry? If you have got chance to go through WhatsApp folders, it actually stores the images of every person that we get the contact image in a direct read directly. It doesn't store it in shared preferences. Okay. Okay. Hi. Hi. I think you talked about the performance with the EOS Red and the images, caching images and all of the good presentation. I would point one thing actually, a question, by using the Android in-built SQL like database, right? Can we have, what kind of performance issues can I have or any difficulties to, because I have used SQL like database, but I have used a small, small query. Yeah, same. So I'm aware of it when you talk about it. So I'm totally aware of it actually. What kind of performance issue I have? Yeah, so in case of, so my, if I need to decide that should I use a database or directly the internal device memory or whatever, it will come from the use case that, what is my use case? There is no key that I want to store that. For this particular thing, I want to store image this, then this. In this case, we just wanted the list of images, not the actually images, that's it. Apart from that, we didn't want to store the whole content. As in case of this, we can actually extend it to next phase, storing the images and downloading them and storing it in DB. That's the next step to it, but for the basic version, for the, you know, the cutoff where I can think of, you know, you can always enhance your app. You can always, you know, add new features, new functionality, new performance to your app. But you need to decide that, oh, this is going to work, you know, slightly for me. This is not going to affect the performance drastically, and that's it. Apart from that, if you, you know, if in future you have a hundred images, then you go ahead with the, you know, storing it in DB, maybe storing it in a device. Thank you. Hi, here. Yeah. So I want to focus on the problem which we saw right now. Internet connectivity, we did not handle that. So in caching, say for example, I cached six images and then while scrolling, I lost internet connectivity. So how do you deal that? I cached six images and when I scroll down, I do not see any images. How do you handle the situation and... Yeah, you don't have internet then. Yeah, but I cached six images. As a user, I will not know that they came from cache, right? Oh, yeah. So in case of shared preferences, when you launch the app, your shared preferences start acting by that time. If you, you know, after some time you come back to your app, shared preferences might not contain that data, and those six images may not be visible. It depends then when I clicked, when I actually launched the app and when the actual server calls were made for images, that time it got loaded and stored. So as a user, I will know that, okay, during this, you know, when images were coming. I mean, when I'm scrolling, say for example, I did not scroll. For the first time I saw six images. Then I scrolled and I lost internet connectivity. So there are six images on the top. There are no images now. So when I scroll down, I mean, when I scroll up, I'll see images. So as a user, I'll not know that they came from cache. I think I got six images and now I'm seeing blank in the bottom. Yeah. So, but you don't have internet connection at that point. Maybe you can have a placeholder. I mean, how, how will we show this to the user that there's no internet connectivity, but I got these from cache or how to handle this situation? Do you, do you actually want to tell your user that it's because of caching? How will we tell the user that it's because of cache? We'll not tell the user that we are storing it in the cache, right? So maybe as a placeholder, you can say that no internet connectivity or something. For every grid or how? It depends upon how you want the interaction to be. For me, I am okay with, if personally, I will be okay with, you know, only six images and if there is no internet connection, then maybe user will have to go back and check your internet connection. That again affects user experience. So he'll be thinking, I got only a few images and I'm not getting others. At least that will be a feedback that at least I got some images. That will be more better than nothing. Your intention was to, you know, if you get all of them, then only start populating. Otherwise, don't show the images. What's your point, Brianna? I'm asking how to deal in this situation. That's it. Yeah, that's it. Cool, thanks. Hi, here. Hello. Yeah. So my question is, have you dealt with out-of-memory errors, which that is very pretty common when you're dealing with images and means especially in low budget phones. So that comes up very often because they have very less memory, very less RAM. Yeah, so I never got through that, but if I start getting that error, maybe I'll switch my shared preference using caching to internal memory or maybe external storing the content in external. If you're asking me that, what should we do in case of, sorry, what should we do? If you're saying that you will change it from this shared preference to external memory, that won't do any good because here out-of-memory error comes from heap, right? And your shared preference, it's not in the heap, right? Maybe for temporary, it's in the heap, but it's stored in the internal memory of the application folder. At the end, right, yes. So the out-of-memory error can come if your thumb, means it's because when, if somebody else, the heap is something that is shared by all the apps, right? It's occupied by some other apps. Yeah, so if some app is very buggy and it takes up a lot of images, it stores it. So the heap may be very less for me to use. And sometimes inflating us even a simple thumbnail itself from the shared preference can cause an out-of-memory error. But don't you think that will be a problem with that buggy app, which is there? No, but how? Do I need to handle it? Yeah, that is certainly, but from a developer perspective, how, I mean, this question totally depends on if you have handled out-of-memory errors. I never got a chance to handle out-of-memory errors. Sorry. Hi. Hi. Yeah. I have this problem, but I didn't expand it thoroughly. Which one is applicable? I mean, advisable. Okay. Writing data that is received from the server as JSON or objects, apply object civilization and then write it. Personally, I would go with JSON, maybe. It has performance issues I've experienced. Yeah, so. Because you're reading it from a file? I don't know. Maybe let's take it as a case-to-case basis what your, how your object is behaving, how big your JSON is, how much are you storing it? Maybe that's how. Because I'm not sure how to handle those kind of problems. Maybe, yeah, we can actually take this case offline going through the content that you have for objects as JSON. Okay, then how does Google+, Facebook does this sync and then store it locally so that we can view the, view things, even when we're offline? Can I answer this question? Yeah. So, basically, there are some libraries like Picasso and there was a talk in like 4 o'clock on Wally. Okay. So, Wally has a networked image view. So, they do cache for me. So, basically, there are many image caching strategies that they use. There are basically two, the best way to do image cache is two levels. One in the memory itself and another in the SD card. So, in the memory you'll be using something called a bitmap LRU cache. Okay. LRU cache is something that keeps track of which bitmap was used, the decent. So, old bitmaps will be quickly recycled. Okay. So, there will be two levels. One will be in the memory itself and one will be in the SD card. There are many libraries. If you just search and there are libraries like Universal Image Loader, Droid View, Ignition. I mean, forget about images, just JSON. No, JSON won't do. Basically, better is that you keep it as a byte array. That's the best way you can do. Okay. Thanks. Thank you. Okay, thank you.