When my application connects to the server I check which icons are outdated or missing.
I store those icons in a sqllite database, the icons aren't very big, around between 5-10kb.
Everytime an activity starts, I'll go to the database and get the necessary icons.
But many of my activities use the same icons, so I was thinking about getting them from the database once, and then cache them somewhere to speed up my application.
How should I do this ?
I was reading this link: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html and they mentioned an lruCache for bitmaps.
But isn't this a bit of overkill for what I'm trying to achieve?
Absolutely no.
The LruCache is the proper approach to cache stuff, it doesn't matter the size of the images.
Remember to create the cache as a singleton element to be accessed equally by any element on your whole application.
DO NOT USE WeakReference as some people will suggest. They do not work very well on the Android, if you're in a search mood you can check the Google IO 2012 talks on YouTube that the Android team themselves are explaining why not use WeakReference and how to properly use LruCache.
edit
found the youtube link
http://www.youtube.com/watch?v=gbQb1PVjfqM&feature=plcp
Your question does not sound like you are asking how to do a memory cache, but whether it's reasonable to do it at all. Does the application already feel like the icon loading is a bottleneck? What else is your application doing? Some networking perhaps? How many activities (out of all activities) actually do have some icons? How many icons per activity do you have? How many icons is there in total? Guessing from #Budius post, doing memory cache right is not completely straightforward issue on Android, so make sure that you are not doing an unjustified premature optimization
Related
Currently, I am using a WeakHashMap to store my BitMap and link it to my key, but I have noticed it begins to use a ton of RAM. Is there a better solution to caching the BitMaps till I need them? It is unlikely I will need the image after the application closes, so a long-term solution isn't really needed.
Thanks!
I need to keep them in memory in case the user swipes back to a
previous view to save bandwidth and make the ViewPager more responsive
FragmentStateAdapter is meant for precisely that. Also use setOffscreenPageLimit() and setRetainInstance() in conjunction with that.
Storing Bitmap objects in runtime memory is not a good idea and will sooner or later lead to OutOfMemoryErrors getting thrown.
It is unlikely I will need the image after the application closes, so a long-term solution isn't really needed.
Storing images in cache wont be a problem as system doesn't clear image from cache even after you close the application or unless you clear the app data from setting.
For image downloading you can use image libraries like:
Image loaders:
https://github.com/nostra13/Android-Universal-Image-Loader
It gives you option to save image in cache.
You can also use volley library. But in this you have to implement your own code for cache storing.
http://developer.android.com/training/volley/index.html
Otherwise you can also implement your own code for cache in which you can use memory disk for caching.
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html#disk-cache
Use an LruCache. There are plenty of online guides on the developer site.
In the spirit of not reinventing the bicycle I'm wondering if there's an Android best practice approach (which I'm not finding through google, but I'm probably not articulating my search correctly) for keeping a defined amount of local storage allocated for downloaded bitmaps, which are kept around based on a most commonly utilized (rather than FILO or FIFO) algorithm.
So, what I'm going to be doing is grabbing an image if it's not already on the disk and storing it and marking it as "most recently needed". The next time it's used I'll be marking it as most recently needed again. Every time I do this I go through all the images and any image that has fallen beyond some threshold of recent utility will be deleted.
My algorithm also takes into account the reality that not all images are created equal and that there's a finite amount of space that I wish to allocate for image storage.
I'm not asking for "how to do this" (because I know how to do it)... I'm asking if there's already a prescribed approach that I should follow before I embark on my own custom implementation.
I think you need LruCahe. you can use UIL and all available caching mechanism or create your own with DiskLruCache. I think most of the libraries use LRU as an algorithm for caching images and I do not think any of them use LIFO or FIFO.
I can recommend the Picasso library for Android. Features as per site:
Handling ImageView recycling and download cancelation in an adapter.
Complex image transformations with minimal memory use. Automatic
memory and disk caching.
I'm not 100% sure if this meets your requirements but it's worth to take a look at.
I am making an attempt to build the most efficient way of caching images downloaded from the web for my app, a few years ago I tried to do this and could not find an efficient method of making this work until I stumbled upon the lazylist adapter found here:
Lazy load of images in ListView
this worked well until android 4.0 was introduced, at this point the app would crash after loading 10 to 20 images, as opposed to before where I could simply load up as many as I wanted without any issues, this I later found out was a result of the Ice cream sandwich having a set limit on memory usage per app, which didnt exist in Gingerbread 2.3 and below, I eventually decided to just clear the cache every 10 or so images to avoid crashing, however the user experience wasn't very good as a result of doing this and the app used tons of data as it was constantly redownloading images over and over again that were already viewed, I have since attempted to use an lru cache but this does not seem to work at all, especially when I leave the app and relaunch it the images are all released it seems, I need a better way of doing this and I have noticed that other apps such as instagram seem to have found a way to cache hundreds of megabytes of images, Im consistently having to manually clear the instagram cache in my settings because it seems that they are to able to store an infinite sized cache that seeming never ejects its contents, does anyone know how to build this kind of cache?
You can try using https://github.com/nostra13/Android-Universal-Image-Loader
library. This does most of the hardwork for you.
the way I wold suggest would be to store the images from the web to the sdcard or something then store the URI where the mage is located. The in your list just load the image from the uri.
If your images are big in size you should probably rezise the image before you save it so that you use less memory and it will load faster since the processing has already been done
BTW the memory limit always existed in android
I'm using Jake Wharton's DiskLruCache lib.
I'm curious about app performance, caching strategy, using caching both in a view and across a whole application. Most of the time, the image won't change.
Let's say for example I have a 320x320 photo on my server. I open the stream, save the image.
In my list views, I show bitmaps and in the detail, I show a larger image. Should I save a thumbnail bitmap too? Is that more efficient?
What is your experience with sharing the cache "object" across the entire app (let's say I have multiple views that might leverage the same data. What are the issues with this?
For the sake of performance and currency, what if the image changes on the server. What's the best strategy to know that it's changed? I don't have access to modified date. Only size and yet, I don't really want to query size every time either. Set a flag in the app on the server and then query the flag?
In a traditional application (if there is such a thing), what's the best practice for clearing the cache from time to time? (indent weirded out.)
(I was inspired to write this after seeing all of the performance improvements by Facebook in iOS. I don't have billions to do caching but I would like to at least be smart about it! LOL)
A lot of these answers depend on the type of app you're writing, how important image updates are (and how likely images will change, etc), and total images produced. Aside from disk caching, you should be using memory caching as well, especially in ListViews and other areas where the same images will be scrolled through repeatedly. Look at LruCache and read the Caching Bitmaps entry from Google.
320x320 is probably too big for a listview, you will likely want to create thumbnails (depending on device, and how you're implementing your listviews).
1) You should be using Disk caching fairly aggressively (how you define that is up to the app you're writing). Use the external storage directory, and if they have a few GB left over, it's not an issue if you take 100 mb for your app for instance. It can all be cleared away if it's ever needed anyway.
2) There shouldn't be an issue. Disk IO (even to a flash medium) should never be handled on the main thread. Use AsyncTasks to load the images. There can only be one main foreground activity at once anyway, and while an activity is sleeping, it shouldn't be trying to read from the disk anyway.
3) Again this depends on how you're implementing your app. You should be able to get additional information when retrieving the file (even Apache can tell your app the last modified date).
3.1) You can have a sqllite db that keeps track of how often certain images are used, and most recent read. If the most recent read is a few days old, let that image expire.
Edit: There's a library from Jake Wharton now called Picasso that I would recommend using, which handles the Network/local IO as well as memory and disk caching. Check it ou here: http://square.github.io/picasso/ . A lot of what you will need to do can be accomplished with one line: Picasso.with(this).load(imageFileURL).into(imageView);
We have an Android application that throws out of memory error on Android 1.6. It is working fine on 2.0 onwards. We are trying to cut down on the runtime memory usage at this point.
We were thinking of reusing images – such as the background image of each screen. Is it possible to load the background image once in the memory at the time of app launch and reuse this cached copy in each screen rather than each screen loading the same background image increasing the overall footprint in the RAM?
We understand that there many other ways and best practices around runtime memory usage. But at this point, we just wanted to know whether this “image reuse” approach is really feasible?
If yes, how can we do this? Will it at all save any memory or the Android OS will still create multiple copies of the same asset for each screen not giving any benefit from the memory perspective?
Thank you very much for your time in reading my post.
If that background image is loaded as a Drawable from a Resource, it's bitmap data is already shared between all Drawables created that way. So no, it probably wouldn't benefit you in your particular case.
Yes you can reuse images.
It is usually done for ListViews where each row contains the same image.
In this case, you can get the Bitmap once in the constructor of your adapter, and reuse it in the getView() method, so you don't have to load it for each row. This trick is presented here
In your case, you could load your background bitmap in the onCreate() method of your main activity, save it as a public static attribute and then re-use it in all your activities.
But I think it won't make that much of a difference and surcharge the code for nothing.
As you are working on tweaking your UI, I suggest you watch the 2009 Google I/O Presentation by Romain Guy, if you did not see it yet. It shows a lot of useful tricks for boosting an UI's performances, especially when it comes to Bitmap manipulation.