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
Related
in a listview, for each item it needs to show some image(drawable) for different item name. If the name are same they show same image. The drawable is specific and cost some time to make it (need remote resource).
So thought maybe cache the drawable and only build new one if it has not been cached.
saw some article "ANDROID DRAWABLE INSTANCES – DON’T SHARE THEM!"
http://loseyourmarbles.co/2013/09/android-drawable-instances-dont-share/,
and here also need to animate the drawable. But test seems not seeing bad behavior (maybe not tested enough)?
So anyone has had similar requirement and experienced whether one drawable instance could be used on multiple ImageView? Is this approach right way to speed up the listview?
Or can one drawable instance be used on multiple imageView?
HashMap<String, Drawable> mNameToDrawnable = new HashMap<>();
public Drawable getDrawable(Context context, String displayName){
Drawable cachedD = mNameToDrawnable.get(displayName);
if (cachedD != null) {
return cachedD;
}
Drawnable d = makeDrawable(displayName); //new Drawable(context.getResources());, etc ……
d.setDecodeDimensions(100, 100);
mNameToDrawnable.put(displayName, d);
return d;
}
If you want to use the cached drawable in your listview and you're worried about some issues with it you might want to call mutate() on your drawable. This might give you a better understanding : https://android-developers.googleblog.com/2009/05/drawable-mutations.html?m=1
I have a 56 drawable in my res folder.
I use them in 2 Fragments.
Is it a good memory approach to create a class that has a static array containing those drawables and call its get method whenever I want to use it?
Or Should I create a private array in each Fragment?
you should create private arrays in the fragment. Having them all in another class will means they will never get destroyed even when your not using them taking up memory. In addition static arrays will get deleted when the app goes into the background for too long, so you would need extra code to reload the array when is resumed if the array is null
You could just create a static int array using the resource ids, here is an example:
public static final int[] DRAWABLE_ARRAY = {
android.R.drawable.sym_def_app_icon,
android.R.drawable.title_bar,
android.R.drawable.ic_menu_compass
};
Then usage of this array could be something like so:
for (int i = 0; i < DRAWABLE_ARRAY.length ; i++) {
context.getResources().getDrawable(DRAWABLE_ARRAY[i]);
}
This way you aren't creating objects that take up a decent amount of memory since these are only resources ids
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.
Hello all having some trouble when I attempt to add an image to a viewflipper page, I am pulling the bitmaps from the db4o database (not sure if it is the encoding or something it uses that is messing me up).
private void setImageView() {
page = (ViewFlipper) findViewById(R.id.viewFlipper1);
int temp = DigPlayDB.getInstance(getBaseContext()).getPlaysDBSize();
for(int j = 0; j < temp; ++j){
test.add(DigPlayDB.getInstance(getBaseContext()).getPlayByInt(j).getImage());
test1.add(DigPlayDB.getInstance(getBaseContext()).getPlayByInt(j).getPlayName());
}
for(int i=0;i<temp; i++)
{
// This will create dynamic image view and add them to ViewFlipper
setFlipperImage(test.get(i));
}
And then for the setting of the image and adding the view to the page
private void setFlipperImage(Bitmap image){
ImageView _image = new ImageView(getApplicationContext());
//_image.setBackgroundDrawable(new BitmapDrawable(getResources(), image));
_image.setImageBitmap(image);
page.addView(_image);
Log.d("db", "" + image);
}
It works right after I add an image to the database but just that image, older images as well as when I restart the application do not load up even though it says they do from a debugging log I set. I am thinking that the last one shows up since it could still be in a cache somewhere, but the older ones that are stored in the database and not in a cache are not encoded correctly or something. Any help would be awesome. Thanks!
Edit: I should mention that "test" is an arraylist of Bitmaps.
Ok, you said in the comment that you store the object as a Bitmap instance. I guess thats a Android or library class.
Don't do that. Only store instances of your own classes. Storing instances of your classes, java.util.collections, arrays and primitives are okay. Everything else is bound to issues: db4o will eagerly try to store any object. This is a issue for library instances. You don't have control of what they do, how they work internally and if they still work after loading.
I think that's whats happening here. As long as the application is running, db4o returns the cached instance of the object, which is fine. After restarting the application, db4o loads the Bitmap object. However the bitmap object isn't intended to be stored with db4o, so it stumbles over wrongly stored internal state.
So, store your picture in a byte-array. Or just as plain file on the SD-card.
I often find myself writing very similar code across projects. And more often than not, I copy stuff over from old projects.
Things like:
Create images with round corners
read density into a static variable & re-use. 4 lines..
disable / hide multiple views / remote views at once. Example:
}
public static void disableViews(RemoteViews views, int... ids) {
for (int id : ids) {
views.setInt(id, SET_VISIBILITY, View.GONE);
}
}
public static void showViews(RemoteViews views, int... ids) {
for (int id : ids) {
views.setInt(id, SET_VISIBILITY, View.VISIBLE);
}
}
I'd love to package these kind of functions into 1 letter / 2 letter class names, i.e. V.showViews(RemoteViews views, int... ids) would be easy to write & remember I hope.
I'm searching for Github recommendations, links and if nothing is found, I perhaps will start a small project on github to collect.
You could take a look at https://github.com/kaeppler/droid-fu, it might be worth to study and eventually extend it. It's a utility framework not only for views but covering other aspects as well.