I have a static Preferences class that hold some application preferences and stuff like that. Is it ok to store reference to ApplicationContext there? I need that reference so i can get cache folder and stuff like that in classes that don't inherit Activity.
You're right to use the ApplicationContext there since if you don't it can cause significant memory leaks.
However, the problem you have is that the static variable may not retain its value. Due to the way that Android handles applications it is possible that your application could be killed and then restarted - usually due to the user switching to other applications - in such a way that your static variable will become null and your code which sets it won't be run. Have a look at this question for a more detailed answer.
It may be possible to work around this problem but testing all the possibilities that may cause your variable to end up null would be time-consuming and error prone. So in my static preference classes I have made any of the methods which require a Context take it as an argument. For example:
static int getSomeIntegerPreference(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).getInt(PREFERENCE_SOME_INTEGER, 0);
}
It's ugly but it works.
Related
I've looked around but never found a straightforward answer to this question. I'm wondering what would happen if I use a pattern that requires me to pass a Context to static methods to do things on the backend. For instance:
public static Observable<CreateThing> createNewThing(String thingName, Context context) { // Passing Context in
return RestNetworker.handleResponse(ServiceGenerator.createService(Service.class).createThing(thingName))
.doOnNext(response -> DatabaseHelper.getInstance(context).createThing(new Thing(response.getThingId(), thingName))); // context used to get instance of DatabaseHelper
}
This method makes an API call and then writes the object to the database locally after a success response. However, I need to pass a Context to create the instance of the database helper. I could alternatively pass the database helper itself, but then I'd be creating the instance (rather getting it, since it's singleton) in the Activity code and I'd rather not do that either.
My question really is: If, say, a user exits the Activity while the API call is in progress, will this Context instance get GC'd and result in an NPE when the response comes back? I've done this kind of thing before and never noticed that issue, but it really seems that there should be some consequence of doing this. I know that other developers must do some things off the UI thread that require a Context, so this should be a relatively easy question to answer.
Thanks guys! Please let me know if you need any more information to provide better context. Heh.
The rule is that you do not pass an instance of the Activity to some object that may keep a reference to it outside of the lifecycle of the Activity. This will cause a memory leak, as the GC will not be able to free the memory allocated to the Activity and the entire view tree contained within. In those instances you pass getApplicationContext().
In cases where the context will only be referenced for the duration of the method call, passing the Activity as this is fine.
In your case, it seems like DatabaseHelper may store a reference to the context, so I would use getApplicationContext() Note that you would not get NPE because the reference was GC if you passed an Activity, that doesn't make sense - if the DatabaseHelper was storing a strong reference, this could not occur (at least on the reference to the Activity itself).
Recently I have found a way to survive configuration changes. What I do is I declare the objects I want to protect as static fields. Is this a good practice?
It's never been a good practice. In my own experience I made a music player app with full of static variables and it's ram usage rocketed to more than 75 mb which is far more than any other of it's kind. The reason is, it stores the value of variable while activity is destroyed. if you have static variable on bitmaps or any other heavy file, it makes memory leaks which is not pleasant to see by user as not all devices got enough resources (ram) to keep up with heavy usage app.
Also static variables often make NullPointerExceptions as these are used by many other activities too and having a variable null may result in total failure of app...
I advise you to store the data in a SharedPreferences and just make one static field like integer and always use that to retrieve values from SharedPrefrences, its very clean and reduces the NullPointers. Moreover just one static makes u have more control over your app... For me it saves time to change 100's of static field rather than changing 1 as it's a lot easy and memory efficient...
I hope, I may help u a little !
Not really. You can cause a memory leak, because one of your static fields can hold a reference to the current Context, which could be destroyed without the reference.
The best way to survive configuration changes is to use the recomended method - Bundles. If you have to store something bigger and/or more persistant - use files, SharedPreferences or a database.
Use static may lead to nullpointer exception. Because when configuration change the current context is destroyed and if you access those context then it throws nullPointer exception.
So sharedPreferences or database is the best option for store the data.
Hope this help :)
One of the approach to retain Activity State, especially during configuration change is to make use of Fragments.
Instead of reinitializing your activity, you can alleviate the burden by retaining a Fragment when your activity is restarted due to a configuration change.
The fragments of your activity that you have marked to retain are not destroyed by Android system, when it destroyed your activity during configuration change.
You can add such fragments to your activity to preserve stateful objects.
Compare to using "static", this Approach is what being advocated at below link:
http://developer.android.com/guide/topics/resources/runtime-changes.html
I assume you can't just put in the bundle in onSaveInstanceState for some (very good) reason. So I think you have to compare with retain fragment.
If you have a static field in your class, like:
static Object myStaticReference;
you will no more worry about all the lifecycle jungle mess with onDestroy, onCreate, onSaveInstanceState of the Activity or Fragment. This will reduce considerably the code rows and make everything just easier to debug and understand. In any case you shall not have any reference in your object to a View, Activity, Fragment, Context and the like.
If for example you have something like this:
public class MyObject {
ArrayList metaData;
Context cntx;
public MyObject(Context cntx) {
this.cntx=cntx;
}
}
Then you still are in the lifecycle jungle, and you will have to pass (and repass) the reference of the context (and any other View relations you have) any time your Activity gets recreated in onCreate and still manage with onSaveInstanceState if there is any need. So in this case it is just useless.
With retain Fragment (which I suppose should be the other way) things are different too. The retain Fragment will last even when the Activity gets recreated, but you have to manage this additional fragment (the good part is that you do not need an UI for this).
In an Android application, is it bad practice to store objects in static fields in these cases?
Application data. Is it bad to keep application data in static variables in a class while the application is running? Currently, I'm storing the data in an instance variable in my Application class. Then classes that need the data can obtain the data from the Application.
Context's etc. Is it bad practice to store a Context (e.g. a reference to an Activity or an Application) in a static field? This can be used in a class that needs e.g. a LayoutInflater or resources. Currently, I am passing the Contexts to methods needing them as arguments.
Yes and Yes. :)
Static Fields. There are a lot of problems with excessive usage of Static fields. Not only they are slower to access by an interesting margin, but also they are prone to be destroyed overnight by Android, and it's usually hacky to check for their references all over the place or fill your getter/setters with if (sSomeStatic == null) { return new SomeStatic()}. It's ok to store a static reference to a class called (for example) ApplicationData where you store some values, hey, we NEED some globals every now and then, but it's so easy to abuse it, that I frown every time I inspect new Android devs' source code.
Yes, store your Application instance in a singleton pattern and use it, but don't add 200 static fields to your Application implementation just because you can do YOURAPP.getInstance().SomeLazyValueYouAddedHere();
That is bad. It leads to bad practices and it will be slower than having a good design where you access hard references.
I could go on forever but there are a lot of StackOverflow discussions (some heated!) about this. If you are here, I'm assuming you're asking for experience; I've been doing Android for a couple of years in different projects and my experience has always been that the less Static, the merrier.
Now the context… oh the Context. Don't store the Context in a hard reference, ever. Or you will leak memory. An activity has references to View and a multitude of other things. If you store the Context, you're storing the activity and things go bad from there. Learn to pass the Context around, use the Application Context whenever possible and if you need to pass it around, do it for very good reasons. Most of the time the App context is enough for getting resources, strings, etc.
If you're going to store the Context, always store context.getApplicationContext(); Never store a static activity context. You can google this too and StackOverflow has some good answers.
If you can afford one and only one Android book, get the BNR one. Even though Android may release new SDKs every now and then, the concepts are completely valid and the patterns the author uses are the right way to deal with Activities, Contexts, Fragments, etc.
UPDATE Your Application should look like this:
public class YourApp extends Application {
private static YourApp sInstance;
public YourApp() {
super();
sInstance = this;
}
public static YourApp getInstance() {
return sInstance;
}
}
And in that case, yes, you are getting the same Static reference to the same App Context.
I like to know some basic stuffs
I am developing an android application and thus it lead me to memory management issues.
Recently watched a video related to memory management by google I found that using a static variable in an activity causes memory leaks even in orientation change of activity as it keeps references to other objects in the activity,The man in video said that using static variable with the help of a static method will solve the issue, I like to know how a static method will solve the issue ?
I like to know the very best way to use static variable in my application for example I have a global class in which I stores some static variables as its name indicates these values will assessed and modified by different activities,
As an example I have a static variable WIDTH and currently update it like this
Global.WIDTH = 12
or get it like int width = Global.WIDTH
from different activites, is this is a correct method ,or do i have to use a static method to get the width like int width = Global.getWidth();,then what's the difference between both of these , what is the best way to do this,
what are other important things we have to keep in mind when dealing with static variables ?
Thank you all and sorry for the long description ...
Static variables can cause memory leaks because they'll never go out of scope, but if you only have a few primitives such as int or long then you won't have a problem.
You need to be careful if you start referring to objects in static variables, especially collections. If a collection never goes out of scope, neither do any of the objects contained within it, and neither do any of the objects they refer to, so there's a chance that the collection will continue to grow and use up more and memory.
The variable in your question, presumably an int, will be OK though.
I have an odd situation where i want to be able to be able to persist a variable in memory.. like a global variable I can pin in the JVM.
Is this possible? I remember doing something similar in college, but can't find it by googling. I have a logic problem that has some artificial constraints that make this the best possible solution.
EDIT 1:
I will need to update the value of the variable.
EDIT 2 :
I appreciate the responses guys. I'm a .net programmer and hadn't used java since college. Thanks again.
Yes, using a static field:
public class GlobalVariableHolder {
public static int globalVariable;
}
Note, however, that this is considered a bad practice and can lead to unexpected results that are hard to debug. The way to not use a global variable is to pass it around as an argument or methods where you need it.
If you are still sure you need this, in order to guard yourself as much as possible, use synchronization. Even better, if the variable is going to be primitive (int, long, etc), you can use AtomicInteger's getAndAdd() or addAndGet() method.
Usually you will end up storing these things in some kind of a global class--a class that is accessible from anywhere and has a controlled number of instances.
Singletons are commonly used for this. If you look up the pattern for a singleton and store your variable in that singleton (add a setter and a getter) you are on your way.
Doing this (as opposed to a public static variable) will give you some level of access control and traceability--for instance you can put debug statements in the getter if you find you are getting unpredictable results.
In the long run setters and getters and singletons are all bad code smells but no where near as bad as a settable public variable.
Later you may want to move the code that manipulates that variable into the singleton object and possibly convert the singleton to something you can fetch via IOC, but having a singleton is a much better place to start than with a public static.
Do you mean something that will exist across multiple invocations of java.exe, or do you mean a single variable that will be the same location in memory regardless of which thread within java.exe access it? Or do you mean a variable that can only be accessed if you're using JRockit? Or maybe just the JVM on your dev machine, but not on another system?
In the first case, you'd need another way to store it, like a config file.
In the second case, like Bozho says, use the static keyword.
In the third case, you'd probably need to use the System class and determine the JVM manufacturer (Assuming that's available from System - I'm not sure off the top of my head, and you'll learn more by looking up the API yourself).
In the fourth case, you're pretty much back to a config file.
Its not going to win any awards but this should work:
package mypackage;
public class MyGlobal {
public static String MY_GLOBAL_VAR = "my variable";
}
Any class within that JVM instance would be able to access MyGlobal.MY_GLOBAL_VAR.
Updated to allow update.