If I have a method like below:
public static void doSomething(Activity aActivity){
//do Something With The Activity
}
Is passing an activity/fragment into a static method a bad idea in terms of memory usage? Could using this method keep a reference to any method alive for the lifetime of the application?
If I have something like this:
public static void doSomething(View aView){
//do Something With The View
}
Would this keep the reference to the view alive for the lifetime of the application?
Would these 2 examples, if used enough, cause memory leaks or OOM issues?
There is nothing wrong with passing Activity or Context as a parameter to a static method. As long as you do not store a reference to the Activity or Context in a static variable there is no memory leak!
Even if you do store a reference in a static variable, this would be a small memory leak, because the next call to the method would overwrite the reference, freeing the previously stored object for potential garbage collection. So there is no chance of a situation where gradually over time all the available memory would be consumed.
Calling a static method and passing it an argument does not create memory leaks.
It is bad practice (as D. Wasser and everyone else tell you) in general to store an Activity / Context / View into a static variable, but:
You can store static variables even from a member method
Android Studio would raise a warning anyway.
Avoid that, and you'll be fine.
Also, from the Android docs:
If you don't need to access an object's fields, make your method static. Invocations will be about 15%-20% faster. It's also good practice, because you can tell from the method signature that calling the method can't alter the object's state.
If you do have a static method that you use to customize (let's say) you Views, I would consider sub-classing the given View and specify it's behavior as a private member function.
Passing something into a static function isn't a potential memory leak. Storing a variable in a static variable is. This technique is perfectly safe. Its one I'd even recommend, as you can pass in variables to the function and store them in extras inside the class that is going to use those extras, reducing the number of places that need to know of their existence and how they're laid out.
From
Passing a activity context into a static method, memory leak potential?
Related
I was wondering whether I should declare my fields static or not inside activities/fragments.
At first I thought I'd make everything static, since every fragment/activity would only have only one instance in memory at a time (is this correct?)
Then I read here at SO that fields marked as static would never be GC'ed, since only only objects (along with their instance variables) are garbage collected. I'm puzzled
Here's how I'm doing it now....
public class Container extends FragmentActivity implements ActionBar.TabListener {
private static ViewPager sPager;
private static ActionBar sActionBar;
private static PagerAdapter sAdapter;
private static DrawerLayout sDrawerLayout;
private static ListView sDrawerList;
private static ActionBarDrawerToggle sDrawerToggle;
//more code...
(I'm sorry if i'm mixing things up here, I'm new to programming...Also English isn't my first language)
Any answers are appreciated.
What is the impact of Static variable ?
Static variables serve as "roots" to the GC. Therefore, unless you explicitly set them to null, they will live as long as the program lives, and so is everything reachable from them.
So, if you declare a view as static what happens is, the reference created to the activity or fragment stays alive even after the activity is destroyed (may be due to change in device orientation) which creates a memory leak.
So should we never use Static ?
Answer is NO. YOU SHOULD USE STATIC CAUTIOUSLY
If a variable or data is intended to be there for as long as the program is running, then it is most definitely not a leak, it is more likely a "permanent singleton". If the OS tries to access a data and if the object is null, it is a bigger issue. So in those case, static is helpful.
If needed, How to handle the static variable ?
Any variable or view you declare as static, should be assigned null in the activity onDestroy Method or any other appropriate method.
Hope this helps.
The objects in your example are a bunch of views and an adapter. Views and adapters have a lifecycle that's tied to the activity that they're part of – if the activity is gone, then the views that it's made up of should also be gone.
Therefore, these objects should not be held in static fields (unless you null those fields in onDestroy(), but really, why bother).
You have a class Container, if you make these fields static, it means these are fields of the class and common for all objects/instances of this class.
You are right, for Activities you will probably only have one instance, but still these fields belong to this one instance, as Barend said in his response, and are not common with others.
Also your point with garbage collection is valid and an important point on mobile devices since resources are limited and memory leaks happen easily when static is not used carefully.
static: Use it if a field is shared between instances of the class and may even exist without any instance existing. If you are unsure, better don't use static.
I am new to Android, and have been reading that memory management is very important in those memory limited apps.
I have read some where that activity's findViewById() is very expensive. So i'm wondering, if it is good practice to store the Views that you will be using as a global variable and reuse the object? Or is it better to run findViewById() everytime i need to use the view?
Thanks,
Kev
If what you mean is static variable by global variable, then never ever do that! If you keep views as static variables, the activities holding the views will leak.
All the views that you see on the screen are attached to a certain activity, and they hold a reference to the activity, if you keep a static reference to one of the views, the activity will never be garbage collected when the activity is killed(either by pressing the BACK key or you call the finish() method on the activity).
As for findViewById(), I don't think you need to care much about the performance of it, it may expose some overhead, but it is only relatively expensive, it's fast enough for most apps.
When you say "store a view as a global variable", I guess you mean "keeping a reference to the view as a private property in the Activity class". This should not be a problem as far as memory is concerned: keeping an additional reference to the view does not mean storing the whole object again in memory.
What you have to keep in mind is that if you keep a reference to an object, the garbage collector will not be able to clean it from memory even if it is not needed anymore. But since your view is probably not supposed to be destroyed before your activity is, keeping a reference to it in the Activity class should not lead to memory leaks.
So in short: if you need to access your view frequently in your Activity class, I would say it's good practise. At least this is what I do, so if anybody disagrees I'd be very interested to know why.
Yes it is better to make Views as member variables of your activity.(in java there are no global variables, the variables that are declared in a class are called member variables).
public MyActivity extends Activity{
private View mView;
public void onCreate(Bundle savedState){
super.onCreate(savedState);
setContentView(layout);
mView = findViewById(id);
}
}
Storing it as a private member of your class is typical for something you will be using multiple times. A pointer to an object like that. Is tiny.
Over the development of an Android app I've come to a collection of utility-type methods that I have put into a static class. All these methods are used across multiple Activities and most of them do not require any information from the calling Activity.
However, I now have some methods that require the Context of the Activity and one that requires the Activity itself. Let me exemplify some of them:
getDeviceNaturalOrientation() - Uses an Activity's
getWindow().getWindowManager().getDefaultDisplay() to access the
displays rotation, width, and height to determine the device's
natural orientation.
getDeviceOrientation() - Similar to the above but to get the current
orientation
createFile() - Uses the Context to to access some resources (strings) and to
create and show some Toasts
Now, my big questions regarding this Utils class are:
So far, each function takes a Context parameter which I pass from whatever Activity I'm on, but would it be OK to create a static Context or Activity variable in the Utils class and set it at the beginning of each Activity (like in onCreate)? This variable would be used in whatever functions require a Context or Activity instance.
Assuming the above is not recommended, is it OK to pass an Activity parameter to a method or is there a reason to only pass an Activity as Context? The methods I use for the device orientation functions above are specific to Activity objects, not Context, so either I pass as Activity or pass as Context and cast into Activity (the latter sounding like a terrible idea).
Also, I am very open to the idea that this Util class may not be the way to go for these methods that require Context/Activity, so I would welcome alternatives that would still prevent having copies of these methods in each activity class that uses them.
1)A static link to a context is likely to cause a memory leak. It means that a reference to the Activity will be kept around in the static variable even after its destroyed, so all of the memory of the activity and all its views will remain valid and not be cleaned by gc. You can do this, but you have to be careful to null out the variable when done. Its better just to avoid it.
2)Its a little bit awkward to pass the activity as an Activity, but no technical reason not to. At that point we're arguing over code cleanliness/maintainability. And there are times where the non-clean solution is just easier. Of course in the cases above I'd rather pass the orientation/display/Resources objects to the function than pass the entire context or make special accessors.
I think following design should be fine when you call from Activity
MyUtility utility=new MyUtility();
utility.getDeviceNaturalOrientation(this);
utility.getFile(this);
And you can define these function like
public int getDeviceNaturalOrientation(Activity activity){
//code
return some_oreientation
}
and like this
public File getFile(Context context){
//code
//return file handler
}
Activity is the subclass of Context so you can even change the design to following
MyUtility utility=new MyUtility(this); //this refer to Activity
utility.getDeviceNaturalOrientation();
utility.getFile();
As long as you pass activity you are fine but if you do following from your activity you will get error from first method call
MyUtility utility=new MyUtility(getApplicationContext());
utility.getDeviceNaturalOrientation(); //will throw exception
utility.getFile();
And, yes first idea is not a recommended way.
I would suggest you to send a WeakReference of your Activity or getApplicationContext() (for those works which can work using it) and don't use static method because it cause memory leaks. Read Developer blog also
In android, I need reference "context" or to say pass "context" to several classes. For this purpose I have implemented a static class which holds the "context" and all other class access context through it.
//let's say I have a static class DataHolder
//and my main acitivity i.e. whose context need to be refrenced
public class DataHolder{
public static Context context;
}
public class MainActivity extends Activity{
public void onCreate(Bundle bundle){
DataHolder.context = getApplicationContext();
}
}
So, is this process ok to be implemented or it is not the right way to reference in Android application.
The issue here is not about efficiency, but about the inherent risks of storing your context statically.
The context can change in many events, the most likely one is changing the device orientation, so you shouldn't relay on it always. I think you should pass the Context in the constructor to each class you think would use it (or, rather, redesign your code so you don't need it where it's not available, although this may be a bit tricky).
In the worst case scenario, you should try to update it as frequently as you can. But, then again, what's the point in having it always accessible? I think the risks are not worth the laziness (sorry if it sounds rude, I don't mean it to) of making a careful app design.
You should definetely avoid it, since it may lead to a memory leak.
Read: Avoiding memory leaks
This means that views have a reference to the entire activity and therefore to anything your activity is holding onto; usually the entire View hierarchy and all its resources. Therefore, if you leak the Context ("leak" meaning you keep a reference to it thus preventing the GC from collecting it), you leak a lot of memory. Leaking an entire activity can be really easy if you're not careful
I have a bug in my code that made me think I don't fully understand the Android Lifecycle. Yes, I have read all the docs and looked at the diagrams, but they seem to talk only about when to save data, when the activity may loose focus or get killed. However, my question is if I don't need to save state, what happens to the variables & their stored values? I expected them to be destroyed to, but a bug in my code seems to indicate otherwise.
In my case here is what happened. I have an activity that launches a custom view (no xml, I just draw bitmaps on the screen in my custom view). The only variable I currently have in my activity is just a variable for my view: GameView gameView;
Now in my view, I declare several bitmaps, simple int and float variable to deal with drawing and on touch events and I have one array of objects that contain small bitmaps, coordinates of each objects and a few other things. One of the variables in my class for this object, is a static variable that represents the current count of how many objects their are. I did it this way, so the instantiation of the objects causes it to track how man objects their are, instead of tracking this outside the object's class.
I expected the static variable to stay the same value across all objects, but I also expected this variable to be destroyed along with all the other variables and objects of that Activity's view once onDestroyed was called for that Activity. However, that doesn't seem to happen. When this Activity is launched again, this static variable still contains its previous value from its last run - even though onDestroyed was called.
Now my question is NOT how to fix this (I can write code differently to fix this bug), but I would like to understand why this happens with this static variable, since it isn't global to the whole application, it only exists inside that Activity's view? Also, this makes me wonder about the rest of the variables in that view - are they destroyed and their memory released or at least their values no longer available the next time the activity is called or do I need to do this myself - even though I didn't need to save any of this state data?
Thanks for any insight into this.
onDestroy is an instance method and any memory it releases (or allows the garbage collector to release) will be of the corresponding instance. Activities are not singleton; there can be more than one instance of an Activity.
Static variables are class variables and are accesible to all instances of that class. They are initialized when the class is loaded, not when each instance of the class is created.
Please see Understanding Instance and Class members for more info. An excerpt:
Sometimes, you want to have variables
that are common to all objects. This
is accomplished with the static
modifier. Fields that have the static
modifier in their declaration are
called static fields or class
variables. They are associated with
the class, rather than with any
object. Every instance of the class
shares a class variable, which is in
one fixed location in memory. Any
object can change the value of a class
variable, but class variables can also
be manipulated without creating an
instance of the class.