I've got the following problem
I want to create many instances of a view (dinamically). Each view can have one of 6 possible icons. What I wanted to do create a static Bitmap so that I can use in in the Draw function withouth having the same icon on memory 40 times....
like so:
public static final Bitmap InstinctBitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.tech), SmallIconSide, SmallIconSide, false);
Obviously this doesn't work because getResources() is not static. Any workaround? Or is this a bad Idea?
The onDraw method of the view keeps telling me that is a bad Idea to instatiate objects in it, so this is the choice I made
Any help would be greatly appreciated.
Related
In this offical blog site, I read below example of memory leak.
http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html
private static Drawable sBackground;
#Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}
To quote the original post "This code is very fast and also very wrong; it leaks the first activity created upon the first screen orientation change. When a Drawable is attached to a view, the view is set as a callback on the drawable. In the code snippet above, this means the drawable has a reference to the TextView which itself has a reference to the activity (the Context) which in turns has references to pretty much anything (depending on your code.)"
I do not understand this part. When the activity is recreated, the onCreate() method will be executed, the static Drawable object sBackground will be attached to the new TextView in the second activity. Meaning that the object sBackground will reference to the new textview instead of the old textview in the first activity, leaving the first activity un-referenced.
Can anybody tell me where is wrong in my reasoning? Thanks in advance~~
Oops, it seems this thread is a duplicate, someone asked exactly the same thing here
Understanding memory leaks in Android application
Sorry for my carelessness.
As far as I know after checking the source of View class, when a Drawable is attached to a view, the view is set as a callback on the drawable. Beside, the view also keep a reference to this Drawable. Please see this link http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/view/View.java#16292.
And because static variable has long lifetime, then every time you recreate activity & set a Drawable to its view, the activity and its Context also keep a reference to the static Drawable. Then take memories as long as variable does.
Is it crucial for performance to have ViewHolder as static in a ViewHolder pattern?
A ViewHolder object stores each of the component views inside the tag
field of the Layout, so you can immediately access them without the
need to look them up repeatedly. First, you need to create a class to
hold your exact set of views. For example:
static class ViewHolder {
TextView text;
TextView timestamp;
ImageView icon;
ProgressBar progress;
int position;
}
It's not crucial for performance, it is about using. If ViewHolder class will not be static - you have to provide instance of parent class:
No enclosing instance of type Type is accessible.
Must qualify the allocation with an enclosing instance of type Type
(e.g. x.new A() where x is an instance of Type).
Edit: misunderstood the question -- it seems you are asking specifically about making it static. That shouldn't be crucial for performance, but the idea is every bit helps.
Final edit here: Static nested class in Java, why?
====
Orig answer below:
It's very nice to squeeze performance out of a heavy ListView (or some other type of recycled AdapterView). However the best way to tell would be to profile the performance somehow.
Also at Google IO 2010 they recommend this method:
http://www.youtube.com/watch?v=wDBM6wVEO70
Edit:
Also here's a link to traceview to profile the performance, though I'm unsure how well it works.
http://developer.android.com/tools/debugging/debugging-tracing.html
It's not mandatory to do that. But when you use to do like this, you are using the views again when your adapter view is null. You are creating a view and assigning values to the view part, and tag the whole view using static class ViewHolder. So when you come back and view is not null, then visible part will come from to get the tag. This is how you will create less object as well less work load on adapter.
I am creating an Android board game similar to, for example, Bubble Pop where I need to use several bitmaps multiple times.
I have a list of Stones (10x10), where each Stone is an object which holds its bitmap and some other values. Lot of bitmaps (stone colors) are same.
Right now i am using something like this for every Stone in the list:
public class Stone extends Point{
private Bitmap mImg;
public Stone (int x, int y, Resources res, Stones mStone) {
...
mImg = BitmapFactory.decodeResource(mRes, mStone.getId());
}
protected void changeColor(Stones newD){
mStone = newD;
mImg = BitmapFactory.decodeResource(mRes, mStone.getId());
}
}
I found several similar questions, but it is all about big bitmaps. Also i found some Android documentation about caching images, but i am not sure if it solves my problem and how to share this cache between all my stones.
What is the best practice, to achive good performance and avoid OutofMemoryError?
You probably don't need cache. Since you should have a limited number of stone colors (thus bitmaps) you can consider holding those graphic assets in one single class (probably static global class or through singleton pattern.
In your Stone class, you just need to hold the stone's color Id and get the drawable from your assets class. (you can save bitmap, but drawable is much more efficient and you may easily change it to allow some animation later)
For example:
// Singleton - look at the link for the suggested pattern
public class GraphicAssets {
private Context mContext;
private Hashtable<Integer, Drawable> assets;
public Drawable getStone(int id){
if (assets.containsKey(id)) return assets.get(id);
// Create stone if not already load - lazy loading, you may load everything in constructor
Drawable d = new BitmapDrawable(BitmapFactory.decodeResource(mContext.getResources(), id));
assets.put(id, d);
return d;
}
}
you could make the Bitmap variable static or static final
I am developing an app which instantiates a bunch of bitmap objects (e.g. buttons, which have cache bitmaps, so they don't have to get rendered again and again)
Now, I realised that when I run and start the app repeatedly on my huawei mobile device, I get an OutOfMemoryException at a point where the app tries to allocate some memory for the bitmaps.
So I guess it's the bitmaps which make trouble. I do know that there is a bitmap.recycle() method though.
Now my question: what is best practice to clean up memory?
Why isn't there some View method like View::onDestroy() which can be implemented for cleanup purpose?
EDIT: example
my "CirclyButton" (extends Button) class always draws a cached bitmap onDraw:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(this.getDefaultBitmap(), 0, 0, paint);
}
private Bitmap getDefaultBitmap(){
if(mBitmapDefault == null){
mBitmapDefault = Bitmap.createBitmap(8*radius, 8*radius, Config.ARGB_8888);
Canvas canvas = new Canvas(mBitmapDefault);
this.drawDefault(canvas);
return mBitmapDefault;
}
return mBitmapDefault;
}
So I guess this allocated data should be recycled somewhere...?
Views don't have an onDestroy method because views usually don't get destroyed, activities do. A view won't just be destroyed if nothing happens to its activity (Unless you inflate a different layout... That's not the case, right?), and if something happens to its activity, you do have a callback getting called.
If there is a recycle() method, make sure you call it. And remove all reference to memory taking objects in the onDestroy, i.e:
#Override
public void onDestroy() {
object1 = null;
object2 = null;
//...
}
So the GC can do its job. I had the same problem with the AdView of AdMob, although they did have a destroy method it didn't really help. But deleting my references of the view fixed the problem.
Provide more information about where are you using your bitmaps, i have some serious experience of working with images and saving memory.
For example in my app i have a list of some data, which display some bitmap in each row. I store my list in a fragment(for fragment support i use compatibility library), and i recycled my bitmaps on this fragment onDestroy method.
Later i decided to optimize my list, so i added scroll listener to my list and started recycling bitmaps, when they are scrolled off the screen.
two days ago i noticed something. I have a spinner over a map activity. In the OnCreate() method of the activity i populate the spinner with data. After that i start the heap analyzer in DDMS i begin to open/close the spinner. I noticed the VM allocate memory when i open the spinner items, but when i close it, the VM do no free this memory. I've tried to start the GC, but the memory is still allocated. i did this 20 times one by one and the allocated memory increased from 3.5MB to 7MB. What is wrong? I found an issue in google groups, but they haven't answered yet.
Spinner memory leak
I rewrite all my code in the spinner adapter, but the issue still remains.
I read some advices in this topic
Avoid memory leaks
There is something i did not get:
When a Drawable is attached to a view, the view is set as a callback on the drawable. In the code snippet above, this means the drawable has a reference to the TextView which itself has a reference to the activity (the Context) which in turns has references to pretty much anything (depending on your code.)
What does it mean? If i have a textview and set it a drawable object (i noticed the drawable is static), the textview object has a reference to the drawable object and the drawable object has a reference to the view too? If this is true, they become undestroyable by the GC because they both have references to each other? What is this back-reference (callbacks) dependencе between the objects?
Sorry I can't help you on your Spinner problem but I can have a try on the second part:
Romain Guy post on android developer blog explain two important things.
First:
When you create a View (TextView, ImageView...) you must not create it with the activity Context
// DO NOT DO THIS
TextView label = new TextView(this);
Otherwise the View get a reference to your activity and will never be deallocated.
Instead, when you create a View programatically, you have to use the application context:
TextView label = new TextView(getApplicationContext());
Second:
When you link a Drawable to an View, it keeps a callback on your activity via the Context. If you leave it, it will leak memory when your activity is destroy.
The thing to do to avoid that is to "set stored drawables' callbacks to null when the activity is destroyed" so for example whith an ImageView:
protected void onDestroy() {
imageView.getDrawable().setCallback(null);
super.onDestroy();
}
You have to do the same for the background drawable...
Hope it helps.