When my singleton is initialized, it is passed a Context (as advised in Android docs). I use that Context to get the ConnectivityManager.
Later I want to access ConnectivityManager again, but this time I don't have a Context (because saving a Context is bad etc).
Is it ok if during the singleton initialization I keep the ConnectivityManager (or any other system service, for that matter)?
I doubt that the reasons to avoid saving app contexts statically apply to system services as well, but I could be wrong.
EDIT the answer to the "duplicate" question ignored the core of my question, which is I don't have a reference to the app context when I need that service.
And the question itself only asks about leaks.
Related
I'm building a android library with some functionality, which will be used by 3rd party apps. Within my library I need to access network related stuff, and need to access Context.getSystemService() to get ConnectivityManager. For e.g. -
ConnectivityManager connectivityManager = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
The problem is that I do not have an activity class, to get context from. So 2 questions -
Is there a way to get the context of the Activity from which my library method was called?
Is it is a good practice to ask the app(calling my library) to pass the app's activity context down to a 3rd party library?
Thanks!
Ideally, you should never pass a context to retrieve a resource. You should pass the resource itself (in this case, the ConnectivityManager). If that's impractical (because you need several resources, or you need to reload them from time to time), or the resource itself is tied to the Context's lifecycle, and the application context is useless, then you should pass the context, but also should make possible to erase the reference if needed, so you can avoid leaks and crashes. For example, add a setContext(Context context) method, and set the context to null when leaving the activity. Is not exactly pretty, but given the fact you don't control the actions of the user, it's the safest bet. A similar option would be to delete the library object reference, but that would not stop any operations your library could be doing with the context until the next sweep of the GC.
Remember, even if your library operates in the main thread, your app can be sent to background anytime.
Just wondering on why the implementors decided for the developers to pass the context (even though the system services seem more like a singleton for the developers, and we mostly don't even care):
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(layout);
I am asking this more because of an implicit fear of leaking memory/context whenever I play with context. Is there a possibility of mis-handling context here ?
In Android, your app's Context is essentially like a pipe connecting it to the system services. A lot of the system services are singletons, but you cannot arbitrarily access them. The Context class acts as a middleman to receive and pass the service you need to you.
LayoutInflater.from(context); simply goes and calls context.getSystemService() using the supplied context, which is your application's.
In essence, you app and Android are two separate things running simultaneously and Context adds as a pipe to connect them.
Because every android service needs context. LayoutInflater is android service. Another declaretion about this;
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
As per android documentation:
Context:
Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.
So "context" holds different environment parameter. These parameters are very much application and system dependents.
"why the implementors decided for the developers to pass the context"
When you creates any activity or creates any dialog or service or anything then it needs several different environment properties in Android. So there should be something which can provides all these information and can perform different task internally according to your operation. In Android, context does it.
Example: If you send Broadcast in Android then it will be received by all broadcast receiver in different activities and application also. These things you does not manages but you can use, everything is already managed by Android that is the reason we mostly don't even care.
Context is provided by system So we don't really need to take much care of memory leaks. If you will look different public parameters(http://developer.android.com/reference/android/content/Context.html ) then you will find that most of the things you can set or simply get. Functionality also are at application level not much system levels. So leaking you need to take care for you code not actually for context.
I want to store the application context in a static member, like this, so I can access it, the shared preferences, resources etc. everywhere.
My question is whether the context can change itself during the application lifetime, so the stored context won't work in a proper way and I can't access shared preferences etc.
Or is the context immutable, so I can use it without any doubt?
Thanks for you answers!
Application context stays unaltered during application lifetime.
Context is immutable during all work of app. And you can use it in static way to get resources, shared preferences, etc.
When you look at the accepted answer of this post, you will find that it is Ok to do this, but handle with care...
There are a couple of potential problems with this approach,
though in a lot of circumstances (such as your example) it will work well.
In particular you should be careful when dealing with anything that deals with the GUI
that requires a Context. For example, if you pass the application Context into the
LayoutInflator you will get an Exception. Generally speaking, your approach is excellent:
it's good practice to use an Activity's Context within that Activity, and the Application
Context when passing a context beyond the scope of an Activity to avoid memory leaks.
Yep, you can use it with shared preferences and get resources etc.
getApplicationContext() function should do it. It shouldn't matter if its mutable.
I've got a quick question on the best way to handle Android contexts. A lot of things (e.g. Service) require that you pass a context as a parameter. At the present time, I have a public static variable that is set to point to getApplication() and I just refer to this throughout my application where a context is required.
Is this ok to do? Or is there a better method to handle this? A lot of my classes don't extend Activity or service and as such, don't have access to this.getApplication().
Everything seems to work ok when I just pass in my static variable.
Is this ok to do?
The Application object, in some cases, will fail to work. For example, it sucks for UI-related stuff.
Dianne Hackborn, a leading Android engineer, has stated her regret at Application existing in the first place.
My general advice is to use Application only when you know specifically why it is superior to using your Activity, Service, etc. There are cases when it is the better answer (e.g., binding to services).
A lot of my classes don't extend Activity or service and as such, dont have access to this.getApplication().
Pass a suitable Context as a parameter, as the Android SDK does.
At the present time, I have a public static variable that is set to
point to getApplication() and I just refer to this throughout my
application where a context is required.
Is this ok to do?
No.
A context applies to the context in which it was obtained. That is, an activity has context for that activity, a service has context for the service, and so on. Now, a lot of folks do what you are doing, and as you observe, it seems to work. That doesn't mean it will continue to work or that it's good design. If that was the proper pattern, Android would have been designed with Context.INSTANCE that is available statically.
An activity, service, and application are contexts (isA). Receivers are passed a context to their onHandlerIntent() method. For all other classes you write, just get used to constructing them with a context. Out of habit, whenever I create a new class, I automatically add a constructor that accepts a context and add a private field to hold it.
When you need a context in a static method, you should pass it in directly as a parameter.
It annoys me when I need to pass the context reference around all over my code. So I am thinking to create a static method to return a reference to the application instance. I am not sure if it is safe to assume there is only one instance of the Application in one application. Apparently, the Application class in Android SDK doesn't provide such method to return the instance reference. So I suspect there must be a reason?
It's probably safe, assuming that your android app lives within a single os process (most do, but this isn't a guarantee on android), but I advise against it.
If you need access to the context/application outside of the places where it's already available (activities, services, broadcast receivers, applications, views, etc), you're probably letting details related to the android environment creep into code that shouldn't know so much about it.
The big exception is static utility methods (e.g. to display a canned dialog that you reuse in your app or similar), in which case passing your context is kind of a convention in the android world (for example, ProgressDialog.show takes a Context as its first argument).
While you can do this, my feeling is that it's probably a band-aid to work around the fact that you have too many components in your code that are unnecessarily tightly coupled to the android environment.