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.
Related
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.
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've checked the suggested solutions and can't find my answer. If the answer is out there, then I'm sorry for posting it again.
I'm consuming a wcf rest service.
In my test activity I do;
private final static String SERVICE_URI = "http://10.0.2.2/Service1.svc";
This will eventually be used in various activities.
So what I want to do is: private final static String SERVICE_URI = [CONSTANT]
so that if I need to re-point the service somewhere else, a single code update will result in dependent activities pointing to the correct location, allowing them to work, rather than having to update each activity.
So: how / where would I create such a constant in Android, and how would I reference it?
Many thanks any help.
The alternative to String Resources, you could do it the via creating Constants class and put your constant value there. This method is not exactly specific to Android, but have been a practice that is used by the Java community frequently.
public class Constants {
public final static String SERVICE_URI = "http://10.0.2.2/Service1.svc";
}
And refer it in other Activity/classes as Constants.SERVICE_URI. If you use this approach, you can use it anywhere even when Context or Application is not available for you.
From what you describe it sounds like you need to look at String Resources.
You can access them from any component in your Android app at any time and they're effectively 'constant' at build time.
EDIT Just to expand on the use of resources...
...take a look at Dororo's answer. All resources (strings, images / drawables and even UI elements such as Buttons etc) are accessed using 'resource IDs'. Any resId, i.e. R.blah is an int representing the resource. As such, it needs to be fetched in the correct way.
With UI elements we use findViewById(...) and with strings we use getString(...) as in Dororo's example.
My point was that the strings are constant at build time so it isn't necessary to declare any variable as final static that represents a string resource as part of any class such as an Activity because you can access any string using the Context.getString(...) method as shown in the link.
When would you want to change this string?
If you want to change it dynamically without issuing updates to the program, you'll want to probably set it globally and then create functions to edit it which can be called whenever you wish to change the address.
If you're happy to only ever change it when the program is updated (which not all users will necessarily do remember) then you'll want to set it as a string resource or just set it globally and slap on final. To access the string from a String resource use:
context.getString(R.string.resource_name)
application.getString(R.string.resource_name)
To create a string resource, open /res/values/strings.xml and create a new string using:
<string name="resource_name">whatever web address here</string>
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.
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.