Dealing with threads - android

What is the proper way to manage threads working in the background?
For example, I have Activity that creates several threads. I need to do following:
1) Destroy all threads when Application is destroyed
2) Pause threads created within Activity if user navigate away from Activity
3) Destroy threads created within Activity if Activity is destroyed
The only thing that come to my mind would be to have all threads variables declared as public the to be able to issue t.destroy() or something similar on these events that I listed above.
First, I am not sure if this is right way at all, and secondly, I don't like it because I will have to change code to make sure I can reference all threads I created.
For example, I have situation where my Activity instantiate new object (ex. LoadImages.class) and that objects creates several thread depending on how many images is to be loaded. The threads are not visible from the calling activity.
So, do I have to pass threads references to calling activity, or there is some way to know who is the parent of the thread and destroy only thread with particular parent Activity?

For LoadingImages I think there is a simple solution: have a public method on LoadingImage called release that will allow it to release its own resources.
If each of your activities is destroying its own threads, I don't see the need for your step 1.

Related

Why is there no Android API for getting the current Activity?

The question, How can I get the current Activity? has been asked dozens of times on Stackoverflow and other sites and there are many proposed approaches. However, all of them have drawbacks in one form or another.
In this posting, I am assuming that there is no solution provided for this in Android's APIs, e.g., something like: Application.getTask().getRootActivity().
Wouldn't it be nice if there was :-)?
So, to be clear, I'm not asking for an answer to How can I get the current Activity?
Instead, I am asking for the reason that such a capability has not been provided. Given that each running app has a task (assuming that the task hasn't been emptied) and each such task has a root Activity, it would seem to be easy to provide access to that root Activity.
The fact that that such access is not provided, when it is so clearly desired, implies to me that there is something fundamental about the Android architecture that I don't understand.
What is it that I'm missing? Why is this information not provided by the Android APIs?
For background, here is a section summarizing some of the approaches that have been proposed. I found the following two links particularly informative (each of the approaches below is presented at one or both of the links).
Links
How to get current foreground activity context in android?
Android: How can I get the current foreground activity (from a service)?
Approaches
Static Hook
Reflection
ActivityManager
Other (Instrumentation, AccessibilityService, UsageStatsManager)`
ActivityManager
The ActivityManager approach only provides the name of the Activity class, not the current Activity instance. E.g., for a Context instance c:
c.getSystemService().getActivityManager()
.getAppTasks().get(0).getTaskInfo()
.topActivity().getClassName()
Reflection
My favorite is reflection, as proposed by _AZ, but that approach is fragile, given that it relies on internals. What I would like to see from Android is this approach provided via a standard API that developers could then safely rely on.
Static Hook
The most common approach is using a static hook to save a reference to the currently running Activity. The hook can be either per-Activity or per-Application. Memory leaks can be avoided by saving/destroying the hook's value (e.g., in onCreate()/onDestroy(), onStart()/onStop(), onPause()/onResume()). However, issues can arise when multiple Activities are involved (e.g., due to overlapping lifecycles -- see below).
I implemented a static hook approach which does the following (to be perfectly transparent, I haven't implemented #1 yet -- I am currently using a per-Activity static hook, which is a bug).
Provides a class that extends Application to provide the hook. The hook contains a Stack; each node in the stack is a simple ActivityInfo class which contains a reference to an Activity instance as well as the state of that instance (CREATED, STARTED, RESUMED).
Provides a class called ActivityTracker that extends Activity. I then extend each of my Activities with ActivityTracker. ActivityTracker uses its lifecycle callbacks to push/pop itself to/from the stack and to update its state -- my other Activities don't have to do anything.
In theory, this would allow me to always know the full state of the task's back stack -- the full set of Activities, including the root Activity, as well as their current state. In practice, however, there is a twist -- when one Activity starts another Activity, their lifecycles overlap. During that period, peeking at the stop of the stack can yield an unexpected Activity instance.
From: https://developer.android.com/guide/components/activities/activity-lifecycle.html#soafa, "Coordinating activities":
Here's the order of operations that occur when Activity A starts
Acivity B:
Activity A's onPause() method executes.
Activity B's onCreate(), onStart(), and onResume() methods execute in sequence. (Activity B now has user focus.)
Then, if Activity A is no longer visible on screen, its onStop() method executes
Of course, this could be managed also. The bottom line is that we do have a global context available for storing information (the Application) and we do have full information about Activity lifecycle transitions, so with enough effort I believe that this static stack-based approach could probably be made pretty bullet-proof.
But in the End
But in the end it feels like I am simply rewriting code which probably already exists internally for managing an Activity back stack, which is why I ask (in case you've forgotten):
Why is there no Android API for getting the current Activity?
UPDATE
In this update, I'll summarize what I've learned from this thread and my own experiments and research. Hopefully, this summary will be useful to others.
Definitions
I'm going to use the following definitions for "Activity Visibility States", based on the Activity State definitions at https://developer.android.com/guide/components/activities/activity-lifecycle.html.
-----------------------------------
Visibility State Definition
-----------------------------------
Not Visible Created+Stopped
Partially Visible Started+Paused
Fully Visible Resumed
-----------------------------------
Issues
The very definition of "Current Activity" is murky. When I use it, I mean the single Activity in the Fully Visible state. At any given instant, there may or may not be such an Activity. In particular, when Activity A starts Activity B, A's onPause() gets called and then B's onCreate(), onStart() and onResume(), followed by A's onStop(). There is a stretch between A's onPause() and B's onResume() where neither is in the Fully Visible state, so there is no Current Activity (as I define it). Of course, there are also situations where a background thread may want to access a Current Activity and there may or may not be an Activity at all, much less a Current Activity.
I've also realized that I may not always need a Current ("Fully Visible") Activity. In many cases, I may simply need a reference to an existing Activity, whether or not it is currently visible. In addition, that reference might be to just any Activity (for situations where I need to pass a generic Activity reference to some API method) or it might be to a specific Activity subclass instance (so that I can trigger some code specific to that Activity subclass).
Finally, there is the need to understand when Activity lifecycle callbacks are called by the main UI looper and how events like configuration changes are handled. For example, if I create a DialogFragment using an Activity intance which is currently in the "Not Visible" state, will it ever get displayed and, if so, when? Along similar lines, it turns out that the onDestroy() and onCreate() methods caused by a configuration change are contained in the same message in the UI's message queue (see Android UI Thread Message Queue dispatch order), so no other messages will be processed between those two callbacks (during a configuration change). Understanding this level of processing seems to be critical, but documentation on it is sorely lacking, if not missing completely.
Approaches
Here is a collection of approaches that can be used to address most of the above situations.
Background
For discussion, assume Activity A and Activity B, where A creates B.
Generally speaking, a "global" variable can be created by making it
"public static" on pretty much any class. Conceptually, extending
the Application class and adding it to the extended class would be
good, but if that's too much work it could be included (for
instance) in one of the Activity classes.
Generic Activity Reference
Useful whenever a generic Activity is needed.
Create a global variable. In both A and B, have onCreate() set it to "this" and onDestroy() set it to null.
Topmost Activity Reference
Useful whenever you want to access the currently visible Activity.
Create a global variable. In both A and B, have onResume() set it to "this". This approach works fine unless all Activities exit, in which case you may need to create a separate flag to indicate that situation. (That flag could be the Generic Activity Reference implementation mentioned above.)
Specific Activity Reference
Useful whenever a handle to a specific Activity subclass instance is needed.
In both A and B: create a global variable in the Activity subclass itself. Have onCreate() set it to "this and onDestroy() set it to null.
Application Context
Useful whenever a Context spanning the lifecycle of the entire app is needed or when you don't care about using a specific Activity Context (e.g., to create a Toast from a background thread).
You can get this from Activity's getApplication() and store it on a static hook.
Handling Configuration Changes
There may be times when you want to stop/start a background thread only across an Activity "session", where I define "session" to include the series of Activity instances which may be created and destroyed due to configuration changes. In my particular case, I have a Bluetooth Chat Activity and an associated background thread to handle the network connection. I don't want to have the connection destroyed and created each time the user rotates the device, so I need to create it only when one doesn't exist and destroy it only if a configuration change isn't underway. The key here is understand when onDestroy() is called due to a configuration change. This can be done with or without fragments. As is often the case, I prefer the non-fragment approach since the fragment approach doesn't seem worth the extra complexity to me.
Approach 1: Without Fragments
In onCreate(), create the background thread if it doesn't exist yet. In onDestroy(), destroy the background thread only if isFinally() returns false.
Approach 2: With Fragments
This works well because the FragmentManager will store fragment instances across configuration changes if setRetainInstance(true) is used. For an excellent example of this, see http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html. The example is for AsyncTasks, but can also be applied to managing a background thread (just create the thread instead of an AsyncTask in the fragment's onCreate() and then destroy the thread in the fragment's onDestroy()).
Closing
Fully understanding these issues requires a deep understanding of how the UI looper processes its message queue -- when Activity callbacks are called, how other messages are interleaved with them, when display updates occur, etc. For instance, if a DialogFragment is created using an instance of a non-visible Activity, will it get displayed at all and, if so, when?
Perhaps some day Android will provide a deeper API to Tasks and their associated backstacks, along with documentation describing the UI's message processing and associated mechanisms in more detail. Until then, more "source code and/or ... empirical analysis" :-).
Thanks,
Barry
If all you want you want to know is which Activity is foremost and accepting user interactions, just create a BaseActivity that extends Activity and override onResume() and save a reference to "this" in a static variable. All of your other activities should extend BaseActivity. You're done.
The short answer I would guess is that only one activity can ever be active at a time in a given app, and that activity obviously knows who it is (it is itself) -- so the only answer any activity can get to "what activity is currently active" can only ever be "you are, silly".
For simple apps with a clear division between the different activity classes, this works fine, and so that's a great percentage of most of the apps in the play store. It doesn't work so hot when you're getting real clever with encapsulation and polymorphism, as I'm sure you've discovered, but I don't think Google is really targeting those types of developers.
Just my $0.02, I don't think you'll get an "official" answer here.

how to start an Activity behind the current one?

In my app, In an special situation I need to start an Activity and put it behind the current showing Activity, I mean if the current Activity, which is being shown by the user was closed, the user now can see the Activity which I just started. how to do that?
You cannot do this.
Activities will always start right away. You cannot manipulate the back stack in the way you want.
You would have to detect the activity closing and then start your new activity then.
You can implement your case by using onDestroy ()
Perform any final cleanup before an activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.
Note: do not count on this method being called as a place for saving data! For example, if an activity is editing data in a content provider, those edits should be committed in either onPause() or onSaveInstanceState(Bundle), not here. This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
Source : http://developer.android.com

Activity's background thread & configuration change

I have seen some discussion here on Stack Overflow related to using Activity.onRetainNonConfigurationInstance() to maintain a background thread started by one instance of an Activity and pass it to the next instance of the Activity which results, for example, when the phone's orientation changes from portrait to landscape.
The discussions do not specify exactly what can be done with the thread wrapped in the Object returned from onRetainNonConfigurationInstance().
For example:
1. Is there a way to actually keep the background thread running using this technique?
2. Do you need to somehow pause the thread when the previous instance of Activity is going away and then restart it again in the new instance?
Can anyone provide a short example?
Any details would be appreciated.
You can return anything you want to onRetainNonConfigurationInstance(). If you have a Thread that you want passed from one instance of the Activity to another, you can either return it directly, or put it inside another object that you return from onRetainNonConfigurationInstance(). You don't need to pause the thread or interact with it in any way. It just keeps running as if nothing happened.
The only thing you need to be concerned about is how the Thread interacts with the Activity (if at all). If the thread will call the Activity back (to indicate progress or something like that) then you somehow need to give the thread a reference to the new Activity, as the old Activity will be dead.
What do you want to do in your background thread?
EDIT (add more details about threads/activities):
Threads have their own lifetimes which are completely disconnected from Activities. If you create a Thread in an Activity and start it, it will run to completion no matter what your Activity does. The only thing that will stop the thread explicitly is if Android decides to kill your process (which it may do if your process contains no active activities).
The thread will continue to run. For an example of what you can do with this, you can check out the android Ignition project and its IgnitedAsyncTask (and related examples).
The idea is that you will maintain a reference to your thread (usually an AsyncTask) somewhere in your Activity, and occasionally your thread (again, especially if it's an AsyncTask) will require a reference to a Context in order to perform some kind of UI update upon the conclusion of its background task. You will need to make sure that the Context (and anything derived from it--like a TextView or the like) to which your thread has a reference is non-null, or else it will crash.
You might use getLastNonConfigurationInstance() to set your Activity's reference to the thread, and then call a setter on the thread to set its Context reference (to avoid any related null pointer crash).

Updating Activity UI from Different Activity Method?

I have a tab widget where one of the tabs is a chat-type feature. I want to update the chat data at an interval (variable depending on whether the chat tab is active or not).
The best approach seemed to be using an AsyncTask in my main TabActivity class, as that would avoid any issues of the chat activity being destroyed while in the background, while an AsyncTask was running. I wanted to ensure that the Activity isn't destroyed and recreated, thus causing my AsyncTask to be unable to modify the actual active Activity's data.
However, now that my AsyncTask is in the TabActivity activity, I don't have a direct way to call my Chat's ListAdapter notifyDataSetChanged() from my onPostExecute() method anymore. Is there a way to get a reference to a given Tab's current Activity from the TabHost/TabActivity?
Or, alternatively, can I assume my chat activity will never be destroyed as a child activity of the TabActivity activity (well, never destroyed while the TabActivity is active at least), and then just put the AsyncTask in the Chat Activity?
Really the best way to do this is to have a thread that runs and periodically gets the chat data. Then from your UI you can poll the thread to get new messages. This way you can have the thread running no matter what happens to the Activity.
If you're using the Intent loading mechanism for your tabhost, then you should be safe in assuming the task won't get randomly killed any more than the TabHost itself (only paused), and you can safely modify views in it (as safely as you could from the TabHost, at least).
But beware: Any activity can be killed at any time (example: if a user clicks on a link in the tab that opens a new activity while your task is still running), including the tabhost itself, which can lead to ugly crashes when the task returns and tries to update the UI of the now-dead Activity. So make sure to either cancel your AsyncTasks on destroy, have the asynctasks check that your activity is still active before returning results (see WeakAsyncTask in the Android source tree), or use an Activity-independent (semi)persistent pollable background-thread solution like CaseyB suggests (cwac-bus is a nice premade solution in that vein).
Alternatively you could just have the AsyncTask's UI-updating code catch all exceptions (I've seen a few apps that do this) and fail silently, but that smells funny to me.
Lately I've used a modified version of the WeakAsyncTask in most places that checks that the activity is non-finished on returning, personally.

Handling UI code from a Thread

I know how to use handlers to update UI elements such as progress bars toasts etc.
The problem I am having is when the context goes away such as the user pressing the back button or the Activity finishing for some reason. This causes my application to crash often.
I tried using getApplicationContext() (Thinking that this would be available throughout my entire application) but this did not work, ever - instead my application crashed!
I put try catch blocks around all UI update code, this works but is it necessary?
So...what is the bast way to handle this?
The problem I am having is when the
context goes away such as the user
pressing the back button or the
Activity finishing for some reason.
This causes my application to crash
often.
You will also get this, by default, if the user changes screen orientation, as the original activity is destroyed and a new one created.
I tried using getApplicationContext()
(Thinking that this would be available
throughout my entire application) but
this did not work, ever - instead my
application crashed!
The application context is useless from the standpoint of manipulating the UI.
So...what is the bast way to handle this?
In the end, what you need is for your thread to deliver an event to the right activity. Some techniques that people have used include:
Use a listener pattern (e.g., service manages the thread, activities register and unregister listeners with the service, thread invokes the listeners on key events)
Put the "current" instance of the activity in a static data member, which the thread uses to find out which one should be used (dangerous due to memory leaks and fails if you need multiple instances)
Limit background threads to ones that cache data, which the activity pulls (e.g., via polling) as needed

Categories

Resources