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.
Related
I'm a bit confused about my new class type I've written.
My class would be used to serve question and options pulled from database for about four thousands concurrent users. (Because exam will start at the same time for all)
Now what class type should I use for making it work faster.
Would it be good if I make it static?
public static List<Questions> getQuestions(String qType){
List<Questions> objListExamsExt = new ArrayList<Questions>();
....
....
....
while (cursor.next()) {
Questions objExamQuestion = new Questions();
objExamQuestion.setQuestion_id(cursor.getString("question_id"));
....
....
....
objListExamsExt.add(objExamQuestion);
}
return objListExamsExt;
}
A case where a static class might be a good idea is when you want to collect related pieces of functionality, but you don't need to have any internal state in any object.
Normally you can create a static Utils class containing a whole bunch of related functions that are accessed outside the context of any specific object instance
A singleton allows a class for which there is just one, persistent instance across the lifetime of an application.A singleton class might be useful if you have some kind of shared resource, such as a database, an in-memory cache, or maybe some specialized piece of hardware like a robotic arm. Many parts of your program might want to use this resource and you might want to have all access to the resource go through a single point. A singleton isn't always the only way to handle these situations, but it's one of the few places I think a singleton might be a good choice.
In your case if getQuestions() is used in multiple places in your application then you can group it together inside a static Utils Class.
I need to access a few of my custom objects in different activities of my application. For this purpose and for the sake of accessibility I have been using static properties for moving data from an activity to another.
For example I have the following class:
public class TrackItem {
public String title, imageUrl, mediaUrl, type, artist, desc;
public static TrackItem track;
}
And for starting an activity:
TrackItem.track = items.get(i); // 'items' is an arraylist defined elsewhere
Intent trackActivity = new Intent(c, TrackActivity.class);
startActivity(trackActivity);
And now inside the TrackActivity I can easily access TrackItem.track and use it's properties.
I just need to know if I'm making a mistake or not? Is there any better way to do this?
The android way of dealing with that problem is to make your class
Parcelable
and pass it with the intent from one activity to another.
If you are initializing your static variables in an activity be aware of loosing data, because in android activity can be destroyed at any point after its state changed to pause. Moreover, your static variables can be erased if the entire application is killed by the system, that is happening rather frequently. Then you'll get the
NullPointerException
trying to access your data.
If you really want to use static members handle their initialization in the
Application
class constructor, so they will be recreated on the start of your application, being killed.
But in general it is not a good practice in android.
I would say it is OK in certain cases, but there might be other more suitable solutions.
You could have a central data store class that uses the singleton principle and therefore would be accessible from everywhere. You would add the item id to the Intent for the new Activity. Then, with the id, you could get the item from the data store.
You could also make the item serializable and just add it to the Intent.
One thing to keep in mind when using static members is that it could lead to a memory leak. Static members are related to the class and are therefore only garbage collected if you either set them to null, or the whole app gets killed and the classloader unloads this specific class.
In general, this is an unsafe practice because it is difficult to keep track of who is manipulating its data. It is much safer to use static variables for bookkeeping information, such as an ID which you can use to go look up the appropriate TrackItem (e.g. in an SQLite database), which is its own object and does not have the chance of something else editing it when it shouldn't be. It terms of OOP, using static variables as shared data breaks encapsulation.
If you are looking to send data around the app, it would be much better to do so either with intents, as others are saying, or with SharedPreferences. Both have the advantage that you are dealing with only one instance of the object at any given time, SharedPreferences have the added advantage of keeping the data around after the app has been killed, so that users can resume with the same track that was playing when they closed the app. And both of these are safer than using static members as shared data fields.
Many times when I have been developing android apps, in order to access some important variables such as getApplicationContext() or other variables such as Buttons or Edittexts, which are normally not accessible outside MainActivity but required in some other class in the same project, I have been using this technique, that is
Within MainActivity (for getApplicationContext() case):
private static Context context = null;
and inside the onCreate method, I do :
context = getApplicationContext();
and I then access the context ( to display a toast message , for example) by using:
Toast.makeText(MainActivity.context,"Message",Toast.LENGTH_LONG).show();
in my other class. Similarly to get or set the text in an EditText variable and so on.
My questions are:
1)Is this the best method for my problem definition?
2)If no, is there a better way?
3)if no, what are the disadvantages of this technique?
3)Can the same technique be extended to functions in the Mainctivity?
EDIT: I do not require another Activity here, rather I am just splitting the task of the app into separate classes (or objects).
My questions are:
1)Is this the best method for my problem definition?
no this is not the best way of solving this.
2)If no, is there a better way?
yes to save static information you should be using something like a headless fragment so that the android framework can handle the garbage collection on unused classes and data
3)if no, what are the disadvantages of this technique?
disadvantages are many :) firstly memory leaking cause that static var cant be garbage collected at all so it stays in memory.
secondly you should not use edit texts from the main activity somewhere else cause there is no garantee that the mainactivity will still be there cause if you move away from it android might kill it to save memory.
all screens should be selfcontained and data must be transfered with intents and Bundles()
3)Can the same technique be extended to functions in the Mainctivity?
create seperate helper classes that sit within a static class like helpers. MainActivity is not a static class and shouldn't be a static class
There are a few immutable variables to be set and used throughout the entire project. Is it correct if I simple have a class with a couple of static fields in it that I can call? Is there a better approach?
The context includes both "regular" Java projects (e.g. web service kind of thing) and Android projects. Example of what I am doing at the moment:
class Settings {
public static final String APP_TAG = "Some name";
public static final String URI = "http://43.12.323.12:8080/Server";
public static final int MAX_NUMBER_OF_PIGEONS = 25;
}
Would loading some proj_name.config be that much better? As of now, I see this alternative as extra work and no benefits.
Yes, it is fine to consolidate "global constants" into a single object like you are doing, but you may want to consider placing all these constants in an XML resource, which allows greater flexibility in customization, localization, etc.
Note that if you elect to go the XML resource file, you will have to pass a context to any consumer of these constants.
You have at least two possible ways of doing this in Android.
The use of SharedPreferences. This way you can save all the information you need in memory. Another
The resource files that are created in your Android project (such as Strings.xml) could help you aswell to keep a some information in a static way in your app.
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.