Bitmap loosing reference on static hashmap? - android

I got an static hashmap in order to be able to instantiate multiple times the same class, and the hashmap will hold all the key-value reference.
class A {
public static final Map<String,Bitmap> map = new HashMap<String,Bitmap>();
// methods
}
So on every instance of the class A, when you call map.get(KEY), you'll always get the same bitmap. I'm getting an "Released unknown bitmap reference" IllegalStateException What am I doing wrong?

Sometimes, if Android needs memory, it deletes some variables.
So if your app is having a lot of big vars like Bitmaps in static variable, they can be deleted sometimes by the system. I had this problem with an app. The only solution I found is that you have to check on your getter if the object exists, if it doesn't, you'll have to recreate it...

Are you calling .recycle() on the bitmap?
If so when you come to get the bitmap from the hashmap it will no longer exist and throw that exception

Related

Does it ocurr serialization when passing objects between Activity's and Fragments

I have a class Crop that isn't Serializable when it comes to passing her trough an intent to another Activity. But if it is from an Activity to a Fragment (trough Bundles), there's no error and I can see the drawable object in the other side with no errors whatsoever.
How can it be serializable in one case but not in the other ?
public class Crop implements Serializable {
private String specieHarvest;
private String specieLocation;
private String specieName;
private Drawable img;
}
First, let's answer your question.
The reason of the behavior you are seeing is that
Passing objects as extras to an activity, will always cause that object to be marshaled/un-marshaled by Android, it is thought of as some kind of IPC.
Passing objects as arguments to a fragment will not always cause your object to be marshaled.
Then when is your object taken apart and reconstructed by Android when sent to a fragment?
It will not be serialized/de-serialized unless the fragment is destroyed and recreated for some reason, otherwise, that object is kept in a map and the same object is returned to you when you call getArguments().
If you even change that object in the Fragment, it will change the original one that was sent, because it is in fact the same reference. CRAZY, right? :)
If you take a look at Drawable class, you will find that it is not Parcelable or Serializable, so don't pass it along in intents/arguments.
Instead, pass an int which can be the resource ID if the Drawable object is in your resources, or you can pass a String path if that is an image that is stored locally somewhere.
Also, passing int or string is much better, because Drawables tend to be large is size, which might cause your app to crash due to size exceeded for an intent extras.
Here's an article where you can read about that as well.

difference between view reference to member variable and local variable

suppose I have an activity, and it contains a TextView. I can initialize the TextView either to a member variable or to a local variable. is there any memory wise difference between these to initialization ?
example :
Activity with local view reference:
public class MainActivity extends Activity{
#OVerride
public void onCreate(Bundle b){
TextView textView = (TextView)findViewById(R.id.my_text_view_id);
}
}
Activity with member view reference:
public class MainActivity extends Activity{
TextView mTextView;
#OVerride
public void onCreate(Bundle b){
mTextView = (TextView)findViewById(R.id.my_text_view_id);
}
}
You should always use the minimal scope. So when you declare a variable you should ask yourself:
"Will I need this variable later in a different function?"
Yes -> Use a member variable
No -> Use a local variable
Edit:
What also to consider is the cost of object creation:
If a function does get called repeatedly it is a good practice to instanatiate an object only once, store it as a member variable and reuse it instead of creating a new instance every time the function gets called.
So the 2nd important question is:
"Will this function get called a lot and do I really need a new instance of the object stored in the variable?"
Yes, often, and no, I can reuse the same object over -> use a member variable. This way the same memory is used and no garbage gets piled up. Use only for large Arrays or objects, it is not needed for simple int vars in loops.
Memory wise global variables are much more prone to memory leaks. The scope any variable depends on its scope. For local variable, the scope is closing braces of the respected method, and variable is automatically garbage collected after the execution of closing braces. Where as global variable will reside in memory until the any object of that class is in memory.
Generally, try to avoid using 'global' variables unless you have good
reason to do .
You can use Local or Global Variable depends upon your Requirement .
Mainly, local variables are that they work within a limited scope means they are declared when a function is called and after ending it the memory taken up by the variable is released.
Finally usage of global variables leads to wastage of memory .

Instantiate variables in class instead of onCreate() wrong?

Is something wrong with this construct in Android?
class A extends Activity {
private Object myObject = new Object();
#Override
protected void onCreate(Bundle savedInstanceState) {
//myObject = new Object();
}
}
Because at some point(s) later I get (sometimes, not reproducible yet) exceptions because myObject is null. I don't know if it's because I have to initialize in onCreate.
Edit: Additional details:
The actual class of myObject is List<Object> (Where Object is a domain specific type)
At some point later in the activity I'm storing myObject as a static field of a "Parameter passer" class and starting other Activity (because I'm avoiding to implement Parcelable. If this is good or bad practice should not be discussed here, unless that's causing my error). In the other Activity I pick up myObject. There it's (sometimes) null.
Edit 2: I don't understand why this object becomes null if I'm storing a reference to it as static field of my parameter passer class (a standalone, dedicated class). That's how garbage collection works, right, it just removes when the objects are not referenced anymore. So since I have a static reference this object should not be removed. According to this thoughts, if they are correct, the problem should be somewhere else.
When you start a new activity your old one goes on the block for possible garbage collection (including any classes instantiated in it, including your parameter passer class), so your object is not necessarily going to be available (which is why you see an intermittent failure.).
I see two option:
1) Pass it along in the bundle with your intent that starts the new activity. As you were trying to avoid this, probably not your best choice.
2) Extend the Application class and store the object in there.
EDIT
I think the accepted answer to this SO Question might fix your issue (and explain what is actually happening).
No. That code is just fine. You can create objects in the constructor.
You may want to check a previous question about it Instance variable initialization in java and the section 3.2.4. Field Defaults and Initializers which basically states that the first case:
private Object myObject = new Object();
is identical to an initialization in the class constructor. (NOTICE onCreate is NOT the constructor).
So, myObject should never be null, except in the case the "new Object()" instruction failed, generating an exception.
Isn't this possible your code is changing the contents of myObject later on the code?

Variable access performance

I'm developing an app that has a DataManager class, which holds an ArrayList<Object[]>. As this ArrayList needs to be used within other classes, I am wondering what would be the most efficient and fastest way of accessing this list, considering this application will be running on the Android platform.
A) create a public static ArrayList<Object[]> data in the DataManager class and reference it within other classes through DataManager.data
B) create a public ArrayList<Object[]> getData method within the DataManager class and have methods within other classes create local variable ArrayList<Object[]> data = mDataManager.getData() for temporary use.
C) ..?
It seems to me B has more overhead due to object creation. Also I read static is faster than non-static?
Option B does not increase memory use, since you will only have one ArrayList object (all the objects that use it just hold a simple reference, not a copy). The objects that use the ArrayList could also store this reference as an instance variable, instead of requesting it from the manager class each time it is needed.
I read somewhere that access to instance variables is slightly faster than accessing class (static) variables, but I don't have the link to the source.
The difference in performance is not likely to be meaningful. However, Option B gives you better encapsulation.

Need to pass an un parcelable object between activities

I have an Object that I need to be able to pass between Activites. It implements Parcelable and I've written all the code related to that.
The problem is that one of the properties of the Object is a Drawable - and really needs to be. Unfortunately, Drawable is neither Parcelable or Serializable. I don't understand how to pass it.
The reason for having the Drawable is that I need to cache an Image that I've downloaded from the internet at runtime. I don't want to cache the images on the filesystem, since this would potentially end up using up a lot of space over time.
I'm putting the image into a Drawable so that I can easily put it into an ImageView.
Any Ideas?
in your Application:
HashMap<String,Object> tempObjects = new H....
public Object getTempObject(String key) {
Object o = null;
o = tempObjects.get(key);
tempObjects.remove(key);
return o;
}
public void addTempObject(String key, Object object) {
tempObjects.put(key, object);
}
and cast the Object to Drawable on the way back. You may also add a boolean param in the get(), and remove the object from the map if it is true, that way you can access a certain temp object more than once, or remove it immediately if you are sure that you won't need it anymore in there
EDIT: sorry for the Exception catch, I pasted the code from a function where I have a HashMap<Class<?>, HashMap<String, Object>> for more detailed temp objects getter, where I am getting one hashMap as a value, and then getting the Object from it, that's why there was an NPE check in the code that I pasted first
You can store your unParcelable data in a custom ContentProvider,then pass the uri references to it.
You can't pass a complex object that isn't Serializable or Parcelable between activities. One option would be to cache the images in your custom Application class, and access them from there in your activity.
MyApplication application = (MyApplication)getAppliction();
Drawable drawable = application.getCachedDrawable();

Categories

Resources