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.
Related
Currently we're making an Android library that contains an Activity. We want to control the exact flow and the state of the activity, but give the user that implements the library control what the UI looks like. Meanwhile, we want to expose the least amount of internal classes.
The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.
The activity makes use of a Model-View-Intent pattern, so we want to expose the immutable state. Without adjustable UI, the Activity and all its' classes are internal. With adjustable UI, a lot more classes have to made public. This increases the risk of breaking changes on updates and exposes our logic.
To expose the UI, several solution were thought of:
Having a static callback on the activity that calls onCreate(), so setContentView() can be set, and calls render(state: State) on every state change. Our classes are shielded as we like, but using a static for this is questionable.
Make the Activity open, so sdk users can subclass it. This means that every class used by the activity, has to be changed from internal to public.The classes which actually should be internal, will be hidden by obfuscating them with ProGuard.
It would be the nicest to pass a function in the Intent, which to my knowlegde is not possible.
Pass a POJO were we define parameters such as background color, which is the most restricting to the sdk user and is not in consideration.
Which solution is the best? Is there another method than the ones we thought of?
The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.
I picture this like so:
Your consumer receives a State, a ViewGroup, and an Actions object, which I'll explain later.
Based on State the consumer is required to create several views and place them as they wish within supplied ViewGroup.
The consumer is also required to register above views using some Actions.register*Button methods.
The above logic is executed inside one callback method. Once said method finished your SDK will verify correctness (all required actions are assigned a clickable view) and proceed.
Now, how to pass this callback method to sour SDK?
1.
It would be the nicest to pass a function in the Intent
This is actually possible with relative ease (and, IMO, some severe drawbacks).
In your SDK create a static Map<Key, Callback> sCallbacks. When your consumer registers the callback using your API, you'll generate a lookup key for it and store it within the map. You can pass the key around as an Intent extra. Once your SDK activity is opened it can lookup the callback using the key from its intent.
The key can be a String or UUID or whatever fits your needs and can be put inside an intent.
Pros:
It's deceptively easy to implement and use.
The consumer can use your SDK from just one file. All the calling code is in one place.
Cons:
You're not in charge where the callback is created. The consumer may create it as an anonymous class inside an Activity, which results in a memory leak.
You lose the callback map when process dies. If the app is killed while in your SDK activity you need to gracefully handle it when the app is restarted.
Variables are not shared across multiple processes. If your SDK activity and the calling code are not in the same process, your SDK activity will not be able to find the callback. Remember that the consumer is free to change process for their activities and even override your own activity process.
The calling point would look something like startSdk(context) { state, parent, actions -> /* ... */ }.
This is by far the most comfortable method for the consumer, yet the weaknesses start to show once you leave the area of a typical consumer setup.
2.
Make the Activity open, so sdk users can subclass it.
As you explained this is not possible without making compromies on your end.
Pros: ?
Cons:
The consumer needs to register their subclass and unregister your original SDK activity in AndroidManifest.xml. I'm assuming the manifest merger is enabled. This is a pain, as I often forget to look here.
The consumer gets easy access to your activity and is free to break it as they please.
Unless your documentation is pristine, the consumer will have a hard time figuring out what to override in your activity.
The calling point would look something like startSdk<MySdkActivity>(context).
I really don't understand the benefits of this option, as a consumer. I lose the benefits of #1 and gain nothing in return. As a developer I can't sanction this 'let the consumer deal with it' attitude. They will break things, you'll get bug reports and you will have to handle it eventually.
3.
Here I'll try to expand on the idea mentioned first in comments.
The callback would an abstract class defined by your SDK. It would be used as follows:
The consumer extends this class and defines the callback body. The class needs to have an empty constructor and be static. Typically it would be defined in its own file.
The class name is passed in an intent to your SDK activity.
Your SDK activity reflectively creates an instance of the callback.
The callback class could have several methods, one could set up menu, one could setup only view hierarchy, one would get the whole activity as parameter. The consumer would pick the one they need. Again, this needs to be documented well if there are multiple options.
Pros:
You separate the callback from the call site (where your SDK is called from). This is good, because the callback is executed inside your activity, completely separated from calling code.
As a result you can't leak the calling activity.
The consumer doesn't need to touch AndroidManifest.xml. This is great because registering your callback has nothing to do with Android. The manifest is mainly for things that the system interacts with.
The callback is easily recreated after process death. It has no constructor parameters and it's stateless.
It works across multiple processes. If, by any chance, the consumer needs to communicate across processes they're in charge of how they achieve that. Your SDK is not making it impossible as in case #2.
You get to keep your classes internal.
Cons:
You have to bundle a proguard rule to keep the empty constructor of each class extending the abstract callback class. You also need to keep their class names.
I'm assuming you'll hide the intent passing as an implementation detail so the entry point could look something like startSdk<MyCallback>(context).
I like this one because it shifts all possible responsibilities from the consumer to you, the SDK developer. You make it hard for the consumer to use the API wrong. You shield the consumer from potential errors.
Now back to the first paragraph. As long as the consumer can get their hands on a context (ViewGroup.getContext()) they're able to access the activity and the application (in that process). If both the calling activity and your SDK activity live in the same process the consumer could even access their prepared Dagger component. But they don't get to override your activity methods in unexpected ways.
I am working on a solution or code that can be embedded inside of an Android APK to track how many times the app has been launched and how long the app has ran for. I know one way to do this is using the ActivityLifecycleMethods in API 14 and in lower versions of Android having code placed in all Activity Lifecycle events or by providing a base Activity class.
1) Is there a way to hook the ActivityLifecycleMethods without the developer having to make any changes to their code outside of dropping additional code into their App?
I believe this answer is no because even with an Enum Singleton it is not loaded until it is referenced. Also the Enum Singleton will go away once the activity is changed since a different class loader is used when activities change.
If I wanted to keep the Enum Singleton around would it be possible to store a reference to the applicationContext and thus it wouldn't be removed when the Activity changes? Is that what google means by
"There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a Context which internally uses Context.getApplicationContext() when first constructing the singleton." on http://developer.android.com/reference/android/app/Application.html
2) I am not a fan of this solution for older API versions. It seems very likely developers could forget to modify their Activity Lifecycle methods or forget to inherit from the created BaseActivity. Are there any other unique solutions for these older platforms? Is there any other approaches that can be done to determine when an activity isn't running? Could any of the following work:
a) User a class loader to ensure the base activity with the proper metrics are always used
b) Implement some type of heart beat. Will a timer stop working if the app is paused or killed? Is there some other way? Could the ActivityManager be used?
You have many Analytic Agents like Flurry to do that.
When ever you want to track an event, you will add it to flurry and inturn it syncs with server after specific time.
You may use the same logic.
Better create a library file with following features:
Start Application
End Application and report time to db.
Track a specific event count and update to db.
Sync the data to server you like to.
Call appropriate events from your app.
What's the best way to save any changes to global state, that would be lost if the process was killed due to low memory etc?
For activities we have onSaveInstanceState() which allows state to be saved when needed.
I would like something similar for global state. Our Application class holds a references to many objects that can be simply reloaded in onCreate() when the app next starts. But we also change the state of some of those objects, and require these changes to be maintained through the app being killed due to low memory etc.
We could of course persist every time changes are made to the objects in memory. But this would be very wasteful.
My current thought is to use onActivitySaveInstanceState() and keep a dirty flag to know only to call it once. But this adds complexity and probably isn't what this method was intended for.
This cannot be a particularly uncommon requirement, but most of the resources on the net focus on just Activity lifecycle. I'd be pleased to learn of a better approach.
There is no concept of Global State and I actually think that you don't need it at all. An app consists of several independent parts which have their own "state". Thus each part is responsible for its own state. For instance, a fragment which shows particular data knows where to get this data and what to do if there is no such data. An activity which shows user settings knows where to get user settings, how to update it and so on. Both of these parts know what to do when lifecycle methods are calling.
You can always store values in your Application class. On a high level, this is very simple, you create a custom MyCustomApplication, that extends the Android Application class. The Applicaiton class only lives, while the App is in scope (including when it's in the background, which is somewhat unpredictable in Android).
Then you would can access this using the getContext().getApplication()
The implementation details are more complex, and you really should extend the Applicaiton into a Singleton, as described in this SO post: Singletons vs. Application Context in Android?
I've been bugged by this for a while. How do I properly handle screen orientation changes while I have a separate Thread / AsyncTask running? Currently, I have
android:configChanges="orientation|keyboard|keyboardHidden"
in my AndroidManifest.xml, but that is not really encouraged:
Note: Using this attribute should be avoided and used only as a last-resort. Please read Handling Runtime Changes for more information about how to properly handle a restart due to a configuration change.
Also, in the 2.3 emulator, it works when switching to landscape, but switching back to portrait fails.
Now, the reason why I use configChanges is because when the user switches orientation, I might have an AsyncTask running, doing some network traffic, and I don't want it stopped.
Is there any other way of doing this, or is there a way of fixing 2.3 to switch back to portrait?
I know about onRetainNonConfigurationInstance, but I'm not sure it would be a good idea to "save" the AsyncTask instance, mainly because the class that extends AsyncTask is not static (so it is tied to the Activity) -- and it needs to be, because in onPostExecute() it calls methods from the Activity instance.
I had a similar problem to your and worked around it by implementing the AsyncTask as part of a class which inherits from Application class. An Application class is available all the life time of the application So you don't have to worry about your AsyncTask getting interrupted unless the whole application will be killed.
To get notified when the task has finished the Activity has to implement a interface which it uses to register itself to the Application class.
When your application is destroyed because of the screen rotation you can unregister your Activity from the Application class and re-register it when it is recreated. If the task finishes between destruction and recreation the result of the operation can be stored in the Application class meanwhile so the Activity can check whether the task is still running or whether the result is already available when it is recreated.
Another advantage is that you have direct access to the applications context because the Application class is a sub class of the Context class.
Take a look the droid-fu library BetterAsyncTask. It is meant to handle this exact case.
http://brainflush.wordpress.com/2009/11/16/introducing-droid-fu-for-android-betteractivity-betterservice-and-betterasynctask/
I already popped up similar question here.
Basically there is an example of how to pause/resume an AsynTask on device rotation. However it still does not fit for all cases (sometimes it is not possible to safely suspend the action, such as a new user creation on a remote server). For those "unsafe" cases you need to code somewhat I'd call a tricky "framework". You will see CommonsWare gives github links to the one.
In my Android application, I overload the Application class, and I updated the tag in my manifest. This application also creates an Android Service.
I have put some logs in the onCreate of my Application class, and I see it being called twice.
The first time is when my application gets launched (this is expected) and then, it's usually right after the Service is being created.
the log also shows that a second instance of the Application is being created.
(I print the "this" value and they are different).
I thought the Application would be created as a singleton.
Is that happening because I create a Service?
Yes, if you used android:process then you have it running in a separate process, so when the service starts a new process is started for it and thus a new Application object for that process needs to be created.
But there is a more fundamental problem - it is just not right for an Application object to start one of its services. It is important that you don't confuse Application with how you may think of an "application" in another OS. The Application object does not drive the app. It is just a global of state for the app in that process. In fact, the Application object is completely superfluous -- you never need one to write an Android application. Generally I actually recommend that people don't use it. It is more likely to cause trouble than anything else.
Another way to put this: what really defines an application is its collection of activity, service, receiver, and provider tags. Those are what are "launched." All an Application is, is something that is created as part of initializing an application's process. It has no lifecycle of its own, it is just there to serve the other real components in the app.
So just ignore Application when designing your app; it will reduce confusion. (In its place, I prefer to use global singletons for such state.)
Also as a general rule, I recommend not using android:process. There are certainly some uses for it, but the vast majority of the time it is not needed and just makes an application use more RAM, less efficient, and harder to write (since you can't take advantage of globals in a single process). It should be obvious to you if you reach a place where there is actually a good reason to use android:process.
A Service should not really be thought of as an Activity, and you're bound to have problems later on if you think this way. Services and Activities can belong to the same application, if you defined them that way in your AndroidManifest.xml, but they behave differently and have different lifecycles. If you want your Service in a different process, then you set android:process="string" in the <service> section to give it a name different from your application name. You won't have access to global variables when it's in a separate process, and you should communicate to your service through Intents. If your service is more complex, you might want to look at making it remotely callable through AIDL. If you want a singleton activity, then set that Activity's launchMode to either singleInstance or singleTask. singleInstance means it will be the first and only instance of this Activity in it's task stack and no new instances will be created for any new Intents. Since it's the only instance of this Activity, it will always be at the top of the task stack, and always in a position to handle new Intents directed at this Activity. If the Activity is declared as singleTask it will also be a singleton but may have other Activities in the same task stack, and may even have Activities at the top of the task stack above it. This is an important distinction to note. Remember this: singleton Activities that are NOT at the top of the task stack cannot handle new Intents, and the Intent will be dropped. If you want your Activity to always be able to handle all new Intents destined for it, then you most likely want to use singleInstance
The problem is that a Service is a component too, with its own lifecycle, just it hasn't got an user interface.
You should check the developer application fundamentals for the alternatives.
I just had this issue and after reading all this, nothing helped. Here is what helped me.
Add the attribute MainLauncher = true to your MainActivity.cs class.