Does static class have the same lifecycle with Android Application? - java

At the very first, my code looks like this. The datacenter class need context to reach SharedPreference.
class App extends Application
{
private DataCenter dataCenter;
#Override
public void onCreate() {
super.onCreate();
dataCenter = new DataCenter(this);
}
}
When I use dataCenter in my activity, I had to getApplicationContext(), and cast to my App, then get the dataCenter object.
And then I searched stackoverflow, and realize I can make App has a static field to reference itself.
class App extends Application
{
private DataCenter dataCenter;
public static App me;
#Override
public void onCreate() {
super.onCreate();
App.me = this;
dataCenter = new DataCenter(this);
}
}
By doing so, I no longer need to call getApplicationContext() and make the casting, just need App.me.getDataCenter(), in my activity class. And also in the App's constuctor, I could even, not to pass context to dataCenter's consctrutor, just ref App.me in DataCenter class directly.
(Q1) I am woundering if what I am doing is OK, any risk here?
After that, I realise if I want to use dataCenter in my activity, "App.me.getDataCenter()" is still too long for me
(Q2) Can I just make the DataCenter class static as it can access App.me to get the context statically?
(Q3) is static class has the same lifecycle with android's Application ? and the Application class always initial first?

First of all, it's better to change scope of the variable me to private, change its name to something better and more descriptive (e.g. instance) and create get() method, which will return instance of the Application. When you leave this variable public, it can be changed and I guess you don't want it.
(Q1) I am woundering if what I am doing is OK, any risk here?
After that, I realise if I want to use dataCenter in my activity,
"App.me.getDataCenter()" is still too long for me
I think, you should use one instance of SharedPreferences class. If DataCenter uses SharedPreferences, you shouldn't mix context of application and activity. You should choose one context and keep using it constantly. In my opinion, context of the application is a better choice, because you may want to use this object in many activities. Moreover, you don't need to call App.me.getDataCenter() everytime in the activity. Just pass it inside the Application class.
(Q2) Can I just make the DataCenter class static as it can access
App.me to get the context statically?
You can, but you should avoid static classes. When you use static classes, it's harder to write unit tests for your application. Moreover, static objects are not elected for garbage collection while the class is loaded. It means, that your application will consume more memory of the device and will be less efficient.
(Q3) is static class has the same lifecycle with android's Application
? and the Application class always initialed first?
Application's Lifecycle shouldn't change while using static variables in class which derives from Application class.

Related

Preventing memory leaks in Android

Is it wise to get a reference to a Context object in every Activity where I need a Context by getting the Application context? I have learned that it can create memory leaks to throw around your Activity's context object but when you create complex Activities it seems that a Context object is almost always necessary. I was previously declaring a Context variable at the top of the Activity class and initializing it with the "this" keyword in onCreate. I already know this can be poor form, but is it ok to initialize the Context object in onCreate calling getApplicationContext()? In other words does this help solve my problem.
Also, is it better practice to limit the use of static variables? If I'm not mistaken, if I call a static method, or reference a static variable from a different Activity, won't that keep the other Activity in memory too?
There is really no need of a Context field in your Activity, as you can always get the context using getBaseContext(), getApplicationContext(), or this (since Activity itself is Context).
You might have to pass your Context to other classes if you want to keep you Activity class thin. This is perfectly ok as long as the lifecycle of those classes is the same as the lifecycle of your Activity. This means, when your Activity is destroyed, no objects should have the reference to the context you passed.
Static methods are extremely good as long as they don't refer to static fields. Use static methods if they don't have a state. Static fields are dangerous for a lot of reasons. So use them only for the right scenarios.
I think you need to understand the differences between Application Context and Activity Context, please refer to the answer here.
But is it ok to initialise the Context object in onCreate calling getApplicationContext()? In other words does this help solve my problem.
Why do you need to initialise a context object? Activity itself is already a context. For example:
Intent intent = new Intent(this, MainActivity.class);
You don't need to initialise a context from application context as the activity context has more capabilities. Please refer to this link.
Also, is it better practice to limit the use of static variables? If I'm not mistaken, if I call a static method, or reference a static variable from a different Activity, won't that keep the other Activity in memory too?
For sending a data from one activity to another activity, you might need parcelable object and bundle, or Event Bus to decouple both sender/receiver activity.
For static method, you might need to group them under a Utility class.

Working with Android Context in non-Activity Class

I often have the Problem, that I cannot use something because of the Context it needs.
For example, if you have a Toast you want to use in a Class for something, you need Context but you cannot use any context, because you are not in an Activity.
Now what I did was, I gave that Class I made a variable "context" which is set in the constructor, but I don't really think this is right.
So how do I handle the context in a non-Activity Class?
Thanks in advance :)
Never keep a reference to context as a member variable or as a static variable, as it might lead to memory leaks as it becomes difficult for the GC to collect the references.
Since you are using context in a non activity class, I assume that class to be some kind of a helper class with static method blocks.
For eg :
public class ToastMessageHelper {
public static void showToast(Context context) {
Toast.makeText(context, "Hello",Toast.LENGTH_SHORT).show();
}
}
It is better to pass context as a parameter to the methods which require the context to execute.
Now, you can simply call,
ToastMessageHelper.showToast(context);
in your activity or a fragment. Hope this helps!
If you aren't in an activity, you can always use getApplicationContext() which will return the context for the app.
Yes you are right, you usually pass the Context to the required object or class which may require it, sometimes you pass it in the constructor, but knowing that the context may change sometimes is better to pass it right in the method. It is up to the developer choose the right scenario.
It is true that in some situations you could need another way to get or pass the context, but usually passing it in the constructor or methods is enough
A sophisticated way to use context in a non-Activity class is the ContextWrapper.
You can read a little bit about this here:
Best practice to pass Context to non-activity classes?
or here
http://itekblog.com/android-context-in-non-activity-class/
You could also use a variable "context" or pass by parameter in a static method and you should be fine, being in mind you can have some issues with this practice.

Intent service singleton

I want to implement a Service that acts like a Singleton.
I need my App to check if the screen is locked, then start a Listener IntentService. If the screen becomes unlocked, it will kill the Listener service.
I created a ScreenLockService that is an IntentService and is called by the Home activity if the user checked the on/off box because I want the Listener to run even if the the App isn't running.
So the Home activity runs and stops the ScreenLockService service which will run and stop the Listener service.
My problem is that the Home Activity creates multiple instances of ScreenLockService which also creates multiple instances of Listener.
So I'd like to have these two IntentServices run as Singletons, but I'm not sure how to do so.
I've checked out a bunch of tutorials, but they're either out dated or not tailored to IntentServices such as:
http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/
Singleton in Android
I can post some example code of what I have if necessary, but all I'm really looking for is a how-to.
Well the basic idea for implementation of the Singleton patterns is to make a private [or protected] constructor (which means it will not be accessible from outside the class). The class also needs a private field of it's own type (e.g. private MyClass myObj;) Next thing you need is the public static method called something like newInstance() which returns the instance of the class via myObj if it's not null, and instantiate it if it is:
public static MyClass newInstance(){
if (myObj == null) {
myObj = new MyClass();
}
return myObj;
}
Of course it can have a more complex implementation (the constructor does not have to be without parameters).
Now this will always create exactly one instance of the desired class. All you need to do is to always call the method newInstance in the place where you need to use your class. If it was already instantiated, it will give you the old instance, if not, it'll create it.
Hope this was the explanation you were looking for.

Android: avoiding passing activity to singletons by storing inside the Application class = memory leak?

I have a few singletons that require context information as they might have to show dialogs. Up until now I've passed the relevant contexts to the singletons, but this is increasingly leading to memory leaks. I was wondering whether storing a reference to the current activity inside the application class might be a way around this problem. Since the variable is overwritten everytime a new activity starts it shouldn't lead to a memory leak, but it's also accessible from all non-activity classes in the app.
Inside my application class:
private static Activity currentForegroundActivity;
public static void setCurrentlyVisibleActivity(Activity activity) {
currentForegroundActivity = activity;
}
public static Activity getCurrentlyVisibleActivity() {
return currentForegroundActivity;
}
Inside every activity:
#Override
public void onResume() {
super.onResume();
App.setCurrentlyVisibleActivity(this);
Inside every singleton:
methodThatRequiresUI(App.getCurrentlyVisibleActivity);
Are there any pitfalls going down this route that you can foresee? I suppose the application class might be cleared from memory by the OS, but if that happened the app itself would restart - it wouldn't lead to a null pointer. The get method might also get called during application startup before the set had been called - but I can write checks to get around that.
Completely avoid using activity context to a singleton object
that.(yeah you know this)
Dont inflate views, dialogs from app context. It will work but it
will exclude styling and other stuff.
Then how?
make utility methods with static methods, pass context as
parameter.
Use delegation (pass anonymous classes, or an
interface)

Is it bad practice to keep data in static variables?

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.

Categories

Resources