While reading this class BitmapFactory
I noticed that almost all methods inside are static.
Wouldn't that cause a memory exception error sooner or later?
Edit* because of another answer I am more curious of another question. Sorry for this
New question:
Would it be good practice to reuse the same class for all activities
through out the entire application?.
Reason being if a bitmap is called in lazyloading where multiple threads are created there will then be a multiple instance of the BitmapFactory classes. Thus, creating multiple Bitmapfactory methods with a return of static Bitmaps.
No, these methods don't keep data/state whatever, it's like a box, you give input, you receive result. And that's all. The only consumed memory will be the class itself which will be done only once.
Related
I am designing an Android application targeting >= API 17. I have created a class, DownloadImageTask which extends AsyncTask, and receives a string (URL) and an ImageView as arguments. In it, I am opening an HTTP connection, downloading an image from a URL, and using BitmapFactory to create a Bitmap object from the data, then setting the bitmap to the ImageView. The end result is a populated list of data which is available to the user to scroll through, with images populating as they can.
This appears to be a good design on the surface - but I am concerned that I am putting my app at risk for an OOM condition, or other violation of the user experience rules. I'd like to know if the way I've designed this is correct, or if not, how I should approach this.
Thank you in advance for your help.
Two considerations to your own approach:
You shouldn't pass the ImageView to the async task because in that way you are coupling your view and your service layer. So send to the async task the URL, and onPostExecute method call to Activity which implement an updateView (or the like) method.
About your OOM, you are right. The problem might arise if you use the original bitmaps which could have larger resolution than required. Therefore you should scale down the images you keep in memory.
The last issue might not be difficult if you use a few images otherwise could be problematic. So if you will be working with a lot of images and you are not forced to implement your own version, you should have a look to the existing libraries. Some are already mentioned:
Glide
Picasso
To draw my sprites in OpenGL i use a single backing bitmap across multiple objects, the Bitmap is reused if size is big enough or recreated if too small. Currently i am using a static Bitmap object but i think this is causing memory leaks even if i am not sure about that.
So, let's say i need a single Bitmap shared between multiple objects, what would be the best approach?
1) Use a single Bitmap as a static reference as i do
2) Use a static weakreference (even if its not suggested in the android dev page here http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html)
3) Use a singleton and then a Bitmap inside it (but this would be like 1)
4) Use an LRU cache and just creating a new bitmap every time i need it to be bigger
1,3 & 4 are essentially all the same. You create a static reference to either your Bitmap directly or to something that holds a reference. The same happens when you use the Application class to "anchor" that bitmap. That class is kept by Android alive and is in this context the same as a static reference.
Whether this is a memory leak or not depends on your definition. Leaked objects are those that are kept safe from the garbage collector by unintentional references to them. So it's certainly not a leak while you want that reference to keep your bitmap.
The problem that arises with cached data that is independent of the life of some Activity, Fragment or in more general terms "task" is that the data will keep memory occupied even if the user is never coming back to your app. The app process is kept alive until Android decides it needs the memory. That time between your last legit use of the bitmap and Android finally killing your app and thereby cleaning the memory can be seen as leak.
If we had magic powers, we could simply clean up the cache once we know that is going to happen. There are some realistic options though:
Using Android's callbacks: understanding onTrimMemory( int level )
time limits on references: e.g. https://github.com/jhalterman/expiringmap
2) is not an option. If you're trying to use WeakReference as cache, you haven't understood what that class is intended for and I honestly don't understand why it is even mentioned in the documentation (weakly referenced objects should be garbage collected as fast as possible once nobody has a strong reference anymore).
SoftReference is intended for "caching" but using it as actual cache is not only broken on Android. It's broken by design because you give the garbage collector the responsibility to maintain a cache for you without telling it how to prioritize objects or how much memory it should keep guaranteed under what conditions. The result is that the GC will clean up the wrong thing or simply everything. SoftReference can be used to in addition to a proper cache that knows how to clean up.
In addition to all of that: be aware that a single Bitmap may not be enough. If you had a look at Tasks and Back Stack you may have noticed that 1 app process can have 2 or more independent tasks in parallel. That means there could be whatever Activity uses the bitmap in different stages. If you don't want to overwrite your cache bitmap between those all the time, you may have to have 1 bitmap per task.
I don't know how to do it per task, but you can easily use a retained fragment to tie the life of your bitmap to that of an activity (ignoring screen rotation etc): http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html / example with bitmap cache https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/util/BitmapCache.java
I think best way is to create Singleton with hard reference plus some methods for recycling and loading, I've created a lot different way Bitmap and graphics loaders and this is probably most efficient and easiest for access way
public class BitmapLoader{
public static BitmapLoader bl;
private static Bitmap b=null;
public static BitmapLoader getInstance(){
if(bl==null)
bl = new BitmapLoader();
return bl;
}
public Bitmap getBitmap(Context c){
if(b==null && c!=null)
b=loadBitmapUsingContectIfNeededOrWhateverYouWant(c);
return b;
}
public void recycleBitmap(){ //for e.g. onDestroy() Activity or other
if(b!=null)
b.recycle();
}
}
keeping loaded Bitmap in LruCache is also good idea
I read about using LruCache from developer.android.com, and I create a blurred Bitmap from one activity and put it into cache, now that I want to access the cached image from another activity but it returned null. Any examples or links on how to properly use cache will be greatly appreciated, thanks!
The LruCache is being instantiated in one class. It won't be accessible from another class. You could try the approach mentioned in this answer
https://stackoverflow.com/a/14325075/2931650
I have to draw a lot of objects on the game screen made of same Bitmap. So, I need to find a good way to reuse bitmap. I have a class where Bitmap is a field, and every object on the screen is an instance of this class (or its subclass). How can the best performance be achieved in this case?
Thanks for advices.
If you make the bitmap field static then only one instance exists. But in this case you need to manage drawing access to this object.
How about having a BitmapCache class which would be responsible for storing/caching/retrieving all the Bitmap objects.
i am new in android and java ... i am reading from couples of day about android parceling tutorial for transfer data or variables values from one activity to other or one class to other ... but i am not so understood about that.
can u tell me that is it necessary to use Parcelable for this purpose because same task can also be perform using static key word for variables as string,int or array type then why parcelable pls explain in detail ..
thanks for explanation in advance please provide comparison with example
While technically both approaches will work, there are a couple of flaws.
The first is that the static variable is static. If you have two instances of the same activity, they will both reference the same static object. This is probably not what you want.
Secondly, it's considered bad practice to access global variables. It makes it difficult to see what is going on, is difficult to test and you someone (another class) can modify your data. This creates some horrendous bugs.
By passing the data via a Parcelable object it is very clear what you are doing and you avoid both of these problems.
Note that this advice is not specific to Android, rather to Java and programming in general.
Static references never get garbage collected so you end up creating something called a memory leak.
You are keeping an object in memory that you don't need and it can't be freed up.
If you instantiate enough objects like this you will get an out of memory (oom) exception which will cause the app to crash.