http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html does not include a release method. Does it mean it will be GC-ed automatically? Thanks.
LocalBroadcastManager does not include a release method. Does it mean it will be GC-ed automatically?
No it will not. But it also does not have to.
It will exist from the point in time you fist call that method anywhere in your app until your app process is killed.
A static method named getInstance that returns you an instance of the class it is in, means in most cases that you're dealing with a singleton.
Singletons are objects that are intended to exist only once in your entire app and they behave like global variables (that is often considered bad for several reasons).
The whole broadcast mechanism would break down if the place in your code that register to receive broadcasts would use a different broadcast manager than the one the broadcasts are send over. The code makes sure that everybody uses the same one by making it a singleton.
LocalBroadcastManager will on the other hand not leak your activity context if you take that as parameter. It will call context.getApplicationContext() to get the application context which is itself a singleton that is safe to keep referenced forever.
The way the code creates the singleton and how to deal with context in singletons is described in further details in this article: Context, What Context? (Note: in a threadsafe way - unfortunately missing in that article)
Related
I have a singleton class with the "block/allow logic" for my VPN tunnel. Packets sent into the tunnel are not emitted, applications are allowed to bypass based on an allowance list, therefore it can behave as a simple implementation of a firewall.
What I want to do is, when I change the Set<String> of blocked application packagenames, I would like the service thread to run vpnservice.builder.establish() again, using this blocked application set.
An obvious choice for this - in case an "ordinary" foreground service if the service extends LifecycleService, as shown here. However, my service has to extend android.net.VpnService, which does not implement LifecycleOwner. A possible implementation (with some modifications needed) is shown here.
My questions are:
Is there a better, cleaner, more elegant way for my VPN service to observe changes in my blockedPackageName Collection, in my singleton class?
If there is not another way, will implementing LifecycleOwner work in the way I expect it (how I described it, basically)?
If(2), is it enough to add lifecycle.handleLifecycleEvent(Lifecycle.Event.XXXX); in my service's onCreate and onDestroy methods (see below)? Do these do anything apart from preventing memory leaks?
//MyVpnService class
#Override
public void onDestroy() {
Log.i(TAG, "Destroyed.");
stopVpn();
//what is the purpose of this line for my goals?
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}
P.S.: I read the official documentation with regards to Lifecycle components, but I could not find enough code examples for my cases to make the matter more clear.
The best solution I find was to send a broadcast with a custom intent from the singleton class, and signing up a broadcast receiver for this intent in the vpnservice class on start.
For sending a broadcast from any class, you need context - lucky for me, I already needed context in my singleton, for which context.getApplicationContext() works fine without leaking.
Let's say we develop an app with web authorisation. We need some "global" service to determine whether the user is logged. If user is logged, the service must provide some data (such as cookies, auth token, etc) to identity user, otherwise the service must have a way to set this data.
There are couple of ways of doing it. We can use static context (singleton or just static fields) to store this data. We also may create some Service to get all this data from.
But what way is recommended by Google? What way is ideologically correct? Perhaps there are other ways to implement that?
Don't know what's recommended by Google but if you need an object that lives as long as your application lives then it would be the Application object.
So subclass your own MyApplication extends Application, define whatever fields you need in there and then declare MyApplication in manifest and access by (MyApplication)getApplication()
Create manager (singleton pattern) that describes your app model. Yes, make sure also that it does not hold context of Activity, Service and etc. If need context, make sure to call getApplicationContext().
Singelton is the simplest way doing it (+design pattern)
But from time to time, there may be problems using singeltons: if the application process is killed, which will happen almost undoubtedly if you leave the app in the background too long, your singleton will be recreated, and so your private int data will be reset to a default value.
Maybe if you don't want to use too much shared data you can use sharedpreferences to avoid this.
Else you could try Extending the Application class.
Hope helps
I have an asynctask that does something, when its done, I want it to broadcast that its done.
usually I would do : context.sendBroadcast(new Intent(MYINTENT)); however asynctask has no context. I've seen a few answers to this questions suggesting sending a reference to the context of the app's activity to the asynctask. but that reference is bad if the user rotates the screen. and manually maintaining the reference is a bad solution (requires too much from the activity creating the asynctask, which I do not control). now the questions are:
1) why is android set up like that ? why do I even need a context to send a broadcast when broadcasts can be registered for and handled by other contexts ?
2) is there a good solution to this problem ? (good = requires as little as possible from the activity creating the asynctask, survives rotations, etc..).
The context that you are using in your AsyncTask right now is the context of your current Activity. By default a screen rotation will destroy the current instance of that Activity and create a new one.
This is (even if it may not seem so at first) intended behavior. The reason for this is that you may want to have different resources (layouts, drawables, etc) for different screen orientations. In order to apply those potentially different resources Android will recreate the Activity on every rotation.
You can counteract that by setting the android:configChanges attribute in your AndroidManifest.xml file but in your case this solution is not recommended.
The proper way of dealing with this problem is to pass the Application Context to the AsyncTask instead of your Activity (Activity inherits from Context). You can do that by calling getApplicationContext() from the instance of your Activity.
Your applications context will persist events such as screen rotation and lives until the system kills the app.
As to why you need an instance of Context to do basic tasks:
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.
This is how the official documentation defines a Context.
Maybe someone can explain this better but for myself this definition is sufficient.
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.