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
Related
I've wondering if it's okay to do this: whenever we pass a Context variable around, could we just get a singleton reference from the Application class instead
For example here is a subclass of Application class with a single static variable pointing to its own instance
public class App extends Application {
public static mApp;
#Override
public void onCreate(){
mApp = this;
}
}
Then when we need to pass a Context to a method from somewhere, can we just do
foo(App.mApp);
Isn't it okay to treat Context as an application variable?
Well it depends on the context in which you are using it. Many times a context is meant to keep hold of things until it's lifescope is complete and then allow garbage collection to take back whatever it was owning.
Other times the context needs to be an activity to handle life cycle call backs such as onNewIntent or onActivityResult.
Keeping a static instance in the parent is just a shortcut to avoid having to getApplication() and cast it as your type of application. I typically make a method for MyApplication.getApplication().doSomething which will return it's own reference of itself as opposed to ((MyApplication)getApplication()).doSomething
Just seems cleaner for coding purposes. But I would be very leary of using the application context everywhere you need a context, it will come back to bite you eventually.
But yes you can certainly store yourself as a static variable to be shared, I do it in most applications, but typically for a specific shortcut purpose of clean maintainable code, not for cheating on getting context from various crevices.
public class App extends Application {
public static App ctx;
#Override
public void onCreate() {
super.onCreate();
ctx = App.this;
}
}
Then in every non contextwrapper inherited class that needs a Context i use it like App.ctx, Ive been using this extensively in my apps and was wondering, is this a good practice or can it lead to memory leak or any other unexpected results?
Regarding the answer provided by Aritra Roy :
There is no guarantee that the non-static onCreate() (where you are
initializing) will be called before any static initialization which
requires the Context
according to google docs :
void onCreate() Called when the application is starting, before any
activity, service, or receiver objects (excluding content providers)
have been created.
Hence, unless your app provide services to other apps which was not my case so far, it is garunteed that any call within your application flow would come after onCreate was called. And static blocks are not called unless needed so any static block would as well be called after onCreate was called.
Your calling code needs to be ready to deal with null values coming
up because of this, which makes the entire thing more inconvenient
not relavant as App.ctx will never be null unless explicitly set to null anywhere on your own code. according to previous point.
This can lead to huge memory leaks issues
That is exactly what i was asking about, this statement can be true or false, but you didnt back it up so its useless. I was actually asking if it can lead and how can it lead to memory leaks.
Can't implement this static Context in a library project because you
can't extend the Application object.
This is incorrect as ive done it myself and it worked well.
IMO its bad practice.
Because if you context for an object or a method of an object its there for a reason and you should pass the specific context that you (Activity,Service, etc.).
I've been writing apps for 4 years and everytime i wrote/saw this type of static context was of lazyness. About the memory leaks- i havent checked it but it could lead to memory leaks. Think about it - if you create a View (i know you wont:) )or other object for example with a static context at the cuntructor (that implies that one of the members need a context attached , most likely) it wont get called by the GC even if its no longer on the activity.
I think it is okay. I have an Android library which implements the same idea (nv-android-base).
From my programming experience of 23 years, what should be blamed here is Android's library design. Although many application life-cycle models such as Applet, MIDlet and Xlet have been designed, implemented and commercially executed in this software industry so far, Android has failed to learn from the experience. Some parts of Android's library tree are terrible in design and android.context.Context is one example among such terrible parts. Android should have provided a means to get the application context from a static context.
This is a bad programming practice. I will highlight few points supporting it,
There is no guarantee that the non-static onCreate() (where you are initializing) will be called before any static initialization which requires the Context
Your calling code needs to be ready to deal with null values coming up because of this, which makes the entire thing more inconvenient
This can lead to huge memory leaks issues
Can't implement this static Context in a library project because you can't extend the Application object.
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