Is having app context in a static member a good practice? - android

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.

Related

Activity seems to be created before application object

I have been receiving some crash reports in the Play Store which initially seemed crazy to me.
Some activities (in 1 case, it's a broadcast receiver) are crashing in onCreate()/onResume() due to NullPointerException.
These activities are using static methods which in turn use the Application singleton [for context], but the object returned is null like if the application object didn't exist at all. From my understanding, the application should always have an instance.
My code is ordinary, the application sets a static field in its onCreate(), and the classes that the activities call use MyApplication.getInstance() which returns the application object.
How can MyApplication.getInstance() return null when called from activities? I have no idea how that could happen.
Of course, I have been unable to replicate this crash.
This mainly happens in Android 6, but I have some reports from Android 8 and 9.
I guess you are doing what the most voted answer says in this question.
However, you should see what many people warn in the comments:
The downside is that there is no guarantee that the non-static
onCreate() will have been called before some static initialization
code tries to fetch your Context object. That means your calling code
will need to be ready to deal with null values which sort of defeats
the whole point of this question. – Melinda Green
.
It's upsetting to see how many upvotes this answer has. You should never hold a static instance to context - for proofs sake, try using Leak Canary (github.com/square/leakcanary) and find the memory leak caused because of this. #people-with-enouhg-rep-and-Android-knowledge, please re-review this answer and act accordingly. This is guaranteed to be used by beginners and it's plain simple wrong. – Crearo Rotar
You should either:
User your Activity context whenever possible and pass it to any other class that needs it.
Or, what I really recommend, set up dependency injection using Dagger2. It is a little difficult to learn at the beginning, but there is a lot of information and tutorials to help you get started. Once you setup Dagger properly, all you need to access you Application context in a null-safe way is Inject it in the corresponding class like this:
public class MyClass {
#Inject
Context context;
...
}
As an alternative to the other answer about dagger dependency injection I just wanted to give an example of getting context from an activity the old fashioned way. If you declare context as a member variable it will be available all over your activity and can be passed to other classes as needed:
public class ExampleActivity extends AppCompatActivity {
private Context mContext;
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
mContext = this;
}
I think I found the cause. In Android 6 auto restore not initializing app, the problem is the same and they identified the cause as being the auto backup feature that was introduced in Android 6. Basically, after a restore from the backup, the app is restarted in a weird way where the Application object is not created before the Activity. We now can reproduce the problem and disabling backup fixes the problem.

What are the downsides of having a static Context variable in an Android application?

In Android programming the single most used parameter that is passed almost everywhere is Context. And we know the purposes it serves. But we can't find out why we should pass it for those purposes, and why not accessing it from a global static place.
Based on Uncle Bob's Clean Code, one way of getting cleaner code is by reducing parameters, making them more meaningful to the task you're doing. Based on this, and based on DRYing parameters, we decided to give it a shot, and create a fully-featured application that has activities, fragments, foreground and background services, notifications, media, etc. and uses many device APIs like camera, GPS, etc. and is a real-world application, and only have one static context initialized at the application creation.
So in the application creation we created a public static Context context variable, and we initialized it using getApplicationContext() method in onCreate() override.
Then instead of passing context like this, getContext, etc. throughout code, we simply used App.context, and we didn't pass it as a constructor parameter to our adapters and other utility functions.
Now after venturing this bold movement, we don't see any problem with our app. Everything works just fine, battery consumption is not changed, at least it's not measureable to us so it's very low. Memory consumption is not changed and we can't measure it. Application performance and speed is not changed measurably.
So we have this really big question in our mind that, what are the downsides on our approach? Why Android guys don't just expose a global context that can be initialized and remove all context parameters from the entire ecosystem, only accessing that global variable anytime they need it?
Please read this blog carefully you will understand Context better.
Static variables defined at global scope of the class and so they also refereed as class member.
You can not control creation and destruction of static variable.
Usefully they have been created at program loading and destroyed
when program unload.
Since static variable are class member, all threads tries to access
them has to be manage.
If one thread change value of a static variable that can possibly
break functionality of other threads.
In my projects, I use the static application context for everything except graphics. The fact is that the application context does not contain information about the style and if you create a widget based on it, then it will have a default style.
On this moment, I have never faced the problems of this approach. Importantly, I do not write tests for my projects. But I'm sure that this will not be a problem.
I also will be very grateful if you point me to the problems of such use of the context. (except testing)
Your application doesn't break because you are using the Application Context: this may not be THE best practice, but it is generally fine.
What you are missing there is that Context is an abstract class with many different implementations (an Activity is a Context, a Service is a Context, the Application is a Context) with different properties and capabilities. The Activity has an entire graphic context associated whit it and a full view hierarchy that can occupy megabytes in memory.
One common mistake (that I did myself in my early days) was to store the Activity in a static field: this led to memory leaks by having two entire views hierarchy in memory as soon as the user puts the app in background, the Activity reaches onDestroy(...) callback and the user opens the app again.

Using Static Application Context

I was having an issue with a handler returning during a screen rotation, meaning that the Activity had not been created yet and causing an error.
I solved this via this post: Static way to get 'Context' on Android?
Which sets up an application level static context to use. I wanted to know how safe this is to use and if there are any instances where I shouldn't use this, as I don't entirely understand it.
Thanks,
Kevin.
No, this is a horrible way to solve it. It means you're using the Application context instead of your Activity context, which is generally wrong and can cause memory leaks. The correct way to do this is to either check for this condition before ding anything that can cause this error, or to catch any exception caused and eat it.
Really the best way to solve this is just to turn off activity recreation on rotation which is and always has been a stupid idiotic idea by Google.
How safe is doing so?
Keeping an instance of the Application context as a singleton is completely safe, understanding as safe that you will not receive a NPE by accessing this instance. The application object is itself a singleton and there is only one per application. Even when the app is killed by the system, the Application object's onCreate() is the first call, so you will always obtain a reference to the Application context.
Can I use it for everything?
Of course, NO. The application context is a suitable context for resource management, like accessing to string values, getting the database instace and such. But it is not a good target for the Android View framework, which requires an Activity context. So, you can use it always when there is not a view related to its use. LayoutInflater, for example, will produce an error if you pass to it an Application context.
I recommend to use the Activity context always when you can, but there is some cases where passing the activity context is not an option, for example if you are creating a database instance when the application is being started.
What about the activity recreation on rotation?
Every Android developer will tell you it is a complete hell to manage this scenario, and it is better for you to lock your activity in vertical or do avoid the recreation of the activity. Beside there is not consistent way to do it across all brands and devices, there are many posts from Google Engineers advocating against doing it because it may produce serious memory leaks and layout problems. Here you have more information.
If you use application context you cannot do certain things like inflating a layout- if you pass the application Context into the LayoutInflater you will get an Exception.
Try to use a Loader instead. The result will not be pushed to the views until the Views are ready.

Android - what effect do different contexts have in code performance? [duplicate]

There has been a lot of posting about what these two contexts are.. But I'm still not getting it quite right
As I understand it so far:
Each is an instance of its class which means that some programmers recommend you to use this.getApplicationContext() as often as possible in order to not "leak" out any memory. This is because the other this (getting the Activity instance context) points to an Activity that is being destroyed each time the user tilts the phone or leave the app etc.. Which apparently the Garbage Collector (GC) doesn't catch and therefore uses too much memory..
But can anyone please come up with some really good coding examples where it would be the right thing to use this (getting the context of the current Activity instance) and the application context will be useless/wrong?
getApplicationContext() is almost always wrong. Ms. Hackborn (among others) have been very explicit that you only use getApplicationContext() when you know why you are using getApplicationContext() and only when you need to use getApplicationContext().
To be blunt, "some programmers" use getApplicationContext() (or getBaseContext(), to a lesser extent) because their Java experience is limited. They implement an inner class (e.g., an OnClickListener for a Button in an Activity) and need a Context. Rather than using MyActivity.this to get at the outer class' this, they use getApplicationContext() or getBaseContext() to get a Context object.
You only use getApplicationContext() when you know you need a Context for something that may live longer than any other likely Context you have at your disposal. Scenarios include:
Use getApplicationContext() if you need something tied to a Context that itself will have global scope. I use getApplicationContext(), for example, in WakefulIntentService, for the static WakeLock to be used for the service. Since that WakeLock is static, and I need a Context to get at PowerManager to create it, it is safest to use getApplicationContext().
Use getApplicationContext() when you bind to a Service from an Activity, if you wish to pass the ServiceConnection (i.e., the handle to the binding) between Activity instances via onRetainNonConfigurationInstance(). Android internally tracks bindings via these ServiceConnections and holds references to the Contexts that create the bindings. If you bind from the Activity, then the new Activity instance will have a reference to the ServiceConnection which has an implicit reference to the old Activity, and the old Activity cannot be garbage collected.
Some developers use custom subclasses of Application for their own global data, which they retrieve via getApplicationContext(). That's certainly possible. I prefer static data members, if for no other reason than you can only have one custom Application object. I built one app using a custom Application object and found it to be painful. Ms. Hackborn also agrees with this position.
Here are reasons why not to use getApplicationContext() wherever you go:
It's not a complete Context, supporting everything that Activity does. Various things you will try to do with this Context will fail, mostly related to the GUI.
It can create memory leaks, if the Context from getApplicationContext() holds onto something created by your calls on it that you don't clean up. With an Activity, if it holds onto something, once the Activity gets garbage collected, everything else flushes out too. The Application object remains for the lifetime of your process.
I think there's a lot of stuff that is poorly documented on the SDK site, this is one of them. The claim I'm going to make is that it seems as though it's better to default to using an application context and only use an activity context when you really need to. The only place where I've ever seen that you need an activity context is for a progress dialog. SBERG412 claims that you have to use an activity context for a toast message, yet the Android docs clearly show an application context being used. I've always used application context for toasts because of this Google example. If it's wrong to do so, then Google dropped the ball here.
Here's more to think about and review:
For a toast message, the Google Dev Guide uses the application context and explicitly say's to use it:
Toast Notifications
In the dialogs section of the Dev guide, you see that an AlertDialog.Builder uses the application context, and then the progress bar uses an activity context. This isn't explained by Google.
Dialogs
It seems like a good reason to use application context is when you want to handle configuration changes like an orientation change, and you want to retain objects which need a context like Views. If you look here: Run Time Changes
There is a caution about using an activity context, which can create a leak. This can be avoided with an application context with the views that are to be retained (at least that's my understanding). In an app I'm writing, I intend to use an application context because I'm trying to hold over some views and other things on an orientation change, and I still want the activity to be destroy and recreated on orientation changes. Thus I have to use an app context to not cause a memory leak (see Avoiding memory Leaks). To me it seems there are plenty of good reasons to use the application context instead of an activity context, and to me it almost seems like you would use it more often than an activity context. That's what many Android books I've gone through seem to do, and that's what much of the Google examples I've seen do.
The Google documentation really makes it seem like using application context is perfectly fine in most cases, and in fact appears more often than using an activity context in their examples (at least the examples I've seen). If it's really such a problem to use application context, then Google really needs to place more emphasis on this. They need to make it clear, and they need to redo some of their examples. I wouldn't blame this entirely on inexperienced developers since the authority (Google) really makes it look like it's not a problem to use application contexts.
I used this table as a guidance for when to use the different types of Context such as Application context (i.e: getApplicationContext()) and activity context , also BroadcastReceiver context:
All merits go to original author here for more info.
Which context to use?
There are two types of Context:
Application context is associated with the application and will always be same throughout the life of application -- it does not change. So if you are using Toast, you can use application context or even activity context (both) because toast can be displayed from anywhere with in your application and is not attached to a specific window. But there are many exceptions, one exception is when you need to use or pass the activity context.
Activity context is associated with to the activity and can be destroyed if the activity is destroyed -- there may be multiple activities (more than likely) with a single application. And sometimes you absolutely need the activity context handle. For example, should you launch a new activity, you need to use activity context in its Intent so that the new launching activity is connected to the current activity in terms of activity stack. However, you may use application's context too to launch a new activity but then you need to set flag Intent.FLAG_ACTIVITY_NEW_TASK in intent to treat it as a new task.
Let's consider some cases:
MainActivity.this refers to the MainActivity context which extends Activity class but the base class (activity) also extends Context class, so it can be used to offer activity context.
getBaseContext() offers activity context.
getApplication() offers application context.
getApplicationContext() also offers application context.
For more information please check this link.
I was wondering why not to use Application Context for every operation which it supports. In the end it lowers chance of memory leak and missing null check for getContext() or getActivity() (when using injected application context or acquired through static method from Application). Statements, like the one by Ms. Hackborn to use Application Context only if needed, don't seem convincing for me without an explanation why. But it seems that I have found an unswear why:
have found that there are issues on some Android version / device combinations that do not follow these rules. For instance, if I have a BroadcastReceiver that is passed a Context and I convert that Context to an Application Context and then try to call registerReceiver() on the Application Context there are many instances where this works fine, but also many instances where I get a crash because of a ReceiverCallNotAllowedException. These crashes occur on a wide range of Android versions from API 15 up to 22.
https://possiblemobile.com/2013/06/context/#comment-2443283153
Because it's not guaranteed that all operations described as supported by Application Context in the table below will work on all Android devices!
Two great examples of when you should use Activity context vs. the Application context are when displaying either a Toast message or a built-in Dialog message as using the Application context will cause an exception:
ProgressDialog.show(this, ....);
or
Toast t = Toast.makeText(this,....);
Both of these need information from the Activity context that is not provided in the Application context.
Application context live untill your application is alive only and it is not depend on Activity Life Cycle but, context keep object long-lived. If the object which you are used temporary, that time use Application Context and Activity Context is used totally oposite of Application Context.

When to call activity context OR application context?

There has been a lot of posting about what these two contexts are.. But I'm still not getting it quite right
As I understand it so far:
Each is an instance of its class which means that some programmers recommend you to use this.getApplicationContext() as often as possible in order to not "leak" out any memory. This is because the other this (getting the Activity instance context) points to an Activity that is being destroyed each time the user tilts the phone or leave the app etc.. Which apparently the Garbage Collector (GC) doesn't catch and therefore uses too much memory..
But can anyone please come up with some really good coding examples where it would be the right thing to use this (getting the context of the current Activity instance) and the application context will be useless/wrong?
getApplicationContext() is almost always wrong. Ms. Hackborn (among others) have been very explicit that you only use getApplicationContext() when you know why you are using getApplicationContext() and only when you need to use getApplicationContext().
To be blunt, "some programmers" use getApplicationContext() (or getBaseContext(), to a lesser extent) because their Java experience is limited. They implement an inner class (e.g., an OnClickListener for a Button in an Activity) and need a Context. Rather than using MyActivity.this to get at the outer class' this, they use getApplicationContext() or getBaseContext() to get a Context object.
You only use getApplicationContext() when you know you need a Context for something that may live longer than any other likely Context you have at your disposal. Scenarios include:
Use getApplicationContext() if you need something tied to a Context that itself will have global scope. I use getApplicationContext(), for example, in WakefulIntentService, for the static WakeLock to be used for the service. Since that WakeLock is static, and I need a Context to get at PowerManager to create it, it is safest to use getApplicationContext().
Use getApplicationContext() when you bind to a Service from an Activity, if you wish to pass the ServiceConnection (i.e., the handle to the binding) between Activity instances via onRetainNonConfigurationInstance(). Android internally tracks bindings via these ServiceConnections and holds references to the Contexts that create the bindings. If you bind from the Activity, then the new Activity instance will have a reference to the ServiceConnection which has an implicit reference to the old Activity, and the old Activity cannot be garbage collected.
Some developers use custom subclasses of Application for their own global data, which they retrieve via getApplicationContext(). That's certainly possible. I prefer static data members, if for no other reason than you can only have one custom Application object. I built one app using a custom Application object and found it to be painful. Ms. Hackborn also agrees with this position.
Here are reasons why not to use getApplicationContext() wherever you go:
It's not a complete Context, supporting everything that Activity does. Various things you will try to do with this Context will fail, mostly related to the GUI.
It can create memory leaks, if the Context from getApplicationContext() holds onto something created by your calls on it that you don't clean up. With an Activity, if it holds onto something, once the Activity gets garbage collected, everything else flushes out too. The Application object remains for the lifetime of your process.
I think there's a lot of stuff that is poorly documented on the SDK site, this is one of them. The claim I'm going to make is that it seems as though it's better to default to using an application context and only use an activity context when you really need to. The only place where I've ever seen that you need an activity context is for a progress dialog. SBERG412 claims that you have to use an activity context for a toast message, yet the Android docs clearly show an application context being used. I've always used application context for toasts because of this Google example. If it's wrong to do so, then Google dropped the ball here.
Here's more to think about and review:
For a toast message, the Google Dev Guide uses the application context and explicitly say's to use it:
Toast Notifications
In the dialogs section of the Dev guide, you see that an AlertDialog.Builder uses the application context, and then the progress bar uses an activity context. This isn't explained by Google.
Dialogs
It seems like a good reason to use application context is when you want to handle configuration changes like an orientation change, and you want to retain objects which need a context like Views. If you look here: Run Time Changes
There is a caution about using an activity context, which can create a leak. This can be avoided with an application context with the views that are to be retained (at least that's my understanding). In an app I'm writing, I intend to use an application context because I'm trying to hold over some views and other things on an orientation change, and I still want the activity to be destroy and recreated on orientation changes. Thus I have to use an app context to not cause a memory leak (see Avoiding memory Leaks). To me it seems there are plenty of good reasons to use the application context instead of an activity context, and to me it almost seems like you would use it more often than an activity context. That's what many Android books I've gone through seem to do, and that's what much of the Google examples I've seen do.
The Google documentation really makes it seem like using application context is perfectly fine in most cases, and in fact appears more often than using an activity context in their examples (at least the examples I've seen). If it's really such a problem to use application context, then Google really needs to place more emphasis on this. They need to make it clear, and they need to redo some of their examples. I wouldn't blame this entirely on inexperienced developers since the authority (Google) really makes it look like it's not a problem to use application contexts.
I used this table as a guidance for when to use the different types of Context such as Application context (i.e: getApplicationContext()) and activity context , also BroadcastReceiver context:
All merits go to original author here for more info.
Which context to use?
There are two types of Context:
Application context is associated with the application and will always be same throughout the life of application -- it does not change. So if you are using Toast, you can use application context or even activity context (both) because toast can be displayed from anywhere with in your application and is not attached to a specific window. But there are many exceptions, one exception is when you need to use or pass the activity context.
Activity context is associated with to the activity and can be destroyed if the activity is destroyed -- there may be multiple activities (more than likely) with a single application. And sometimes you absolutely need the activity context handle. For example, should you launch a new activity, you need to use activity context in its Intent so that the new launching activity is connected to the current activity in terms of activity stack. However, you may use application's context too to launch a new activity but then you need to set flag Intent.FLAG_ACTIVITY_NEW_TASK in intent to treat it as a new task.
Let's consider some cases:
MainActivity.this refers to the MainActivity context which extends Activity class but the base class (activity) also extends Context class, so it can be used to offer activity context.
getBaseContext() offers activity context.
getApplication() offers application context.
getApplicationContext() also offers application context.
For more information please check this link.
I was wondering why not to use Application Context for every operation which it supports. In the end it lowers chance of memory leak and missing null check for getContext() or getActivity() (when using injected application context or acquired through static method from Application). Statements, like the one by Ms. Hackborn to use Application Context only if needed, don't seem convincing for me without an explanation why. But it seems that I have found an unswear why:
have found that there are issues on some Android version / device combinations that do not follow these rules. For instance, if I have a BroadcastReceiver that is passed a Context and I convert that Context to an Application Context and then try to call registerReceiver() on the Application Context there are many instances where this works fine, but also many instances where I get a crash because of a ReceiverCallNotAllowedException. These crashes occur on a wide range of Android versions from API 15 up to 22.
https://possiblemobile.com/2013/06/context/#comment-2443283153
Because it's not guaranteed that all operations described as supported by Application Context in the table below will work on all Android devices!
Two great examples of when you should use Activity context vs. the Application context are when displaying either a Toast message or a built-in Dialog message as using the Application context will cause an exception:
ProgressDialog.show(this, ....);
or
Toast t = Toast.makeText(this,....);
Both of these need information from the Activity context that is not provided in the Application context.
Application context live untill your application is alive only and it is not depend on Activity Life Cycle but, context keep object long-lived. If the object which you are used temporary, that time use Application Context and Activity Context is used totally oposite of Application Context.

Categories

Resources