What is the common practice to handle relation between Activity and Thread - android

I have the following situation
I spawn a long running user thread (Thread) from an Activity.
I press soft back button. So, the Activity was destroyed.
I launch the same Activity again. Note, the previous launched Thread is still running.
In order for me to prevent the Activity from launching another same Thread while the previous Thread is still running, here is what I am doing
After I launch the Thread, I will store it into a static variable. So, next time when I try to launch a same thread, I will check against the liveness of previous thread through the static variable. Is this a good practice? What is the best practice to overcome this?
Note, the user thread is holding reference to the Activity which launched it. However, the Activity might destroyed when user press on soft back button. So, when I launch the new Activity again, the thread is not aware of that, and it is still referring to old Activity. So, when user thread try to access any members of the old Activity, crashes will happen as the Activity already being destroyed. What is the best practice to overcome this?

The best way to overcome this is to use an AsyncTask instead. If the Activity is destroyed while the task is executing, the AsyncTask (and its underlying Thread that is performing the operation) will continue its execution until doInBackground() has completed. If the Activity is null by the time onPostExecute is called, you won't run into any NullPointerExceptions for the reasons stated in this blog post.
If you want to immediately cancel the task if the user "backs out" of the Activity, you can call mTask.cancel() on your AsyncTask in your Activity's onDestroy method.
If you don't want to immediately cancel the task if the user "backs out" of the Activity, then your long-term operation doesn't sound like it is specific to any Activity instance. In this situation, it is often advised to use a Service instead.

Related

Using context reference after activity be finished

I have a complete button in page, when user click button, it will start an async task and pass the activity context into it, then finish the activity to dismiss the activity view.
What will happen if the activity be finished but the background task still need to use the context reference passed in? will it have any concerns? or have alternative/better way for this kind of situation.
any suggestions will be appreciated!
First of all, in this situation you better go for service instead of asynctask. In your case, Service should stop itself once task is finished.
Even if you go for asynctask, try to use application context that you can get from activity context as below:
activity_context.getApplicationContext();
The application context will be there even if activity is finished and also it will avoid memory leak.
And if you want to make the asynctask run safely even if activity is finished, then try not to update any UI in postExecute(..) method as it will run on the UI of the activity which is already finished leading to exception. Try to do only any background task inside doInBackground(...) which runs on different thread.
Hope this answers your question.

idle timeout for android app activity

I am writing an Android app (ICS) for a tablet. The user moves from Activity A to Activity B to Activity C with the touch of a button. I want to return from Activity C to Activity A after 10 seconds. Is there some way to count to 10 without locking up Activity C?
I've succeeded with an asyncTask but if I startActivity(A) in the onPostExecute() it feels like I'm violating the guideline that an asyncTask should not mess with the UI. I've tried get() but that does lock up Activity C while it's waiting for the 10 seconds to pass.
Thanks in advance!
Assuming you have any View instance in your activity, you can use View.postDelayed() to post runnable with a given delay. In this runnable you can call Activity.finish(). You should also use View.removeCallbacks() to remove your callback in onDestroy(), to avoid your callback being called after user already navigated back from your activity.
Using AsyncTask just to count some time is just an overkill (unless you want to use AsyncTask to actually do some useful, background work). The Looper and Handler classes provide everything you need to execute any code on UI thread after a given delay. The View methods mentioned above are just convenience methods exposing the Handler functionality.
Using AsyncTask works fine as you describe. From Android Documentation:
onPostExecute(Result), invoked on the UI thread after the background computation finishes.
Since it is invoked on UI thread you should be fine.
Documentation
You can use a alarm manager for that. Set it to send a broadcast 10 seconds starting from activity a and implement a base activity for activity a b and c to receive the broadcast, after receiving the broadcast just end the current activity and start activity a with a new flag. If the current instance is activity a then ignore if not start activity a. Something like that.
As for the idle part you can update the alarm manager on every action, upon entering activity etc.
The advantage of this implementation is that you dont have to go through the hassle of having to worry about context leaks, persisting timers across activities and such. and can make use of what is already there. You can also consider using a service though.
If not you can just use the shared preference store the time to time out and check or update against it for the actions.. A simpler implementation.
Good luck.

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).

Can AsyncTask started from Activity cause problems if Activity is exited?

If I have an AsyncTask started in an Activity by user interaction. The AsyncTask, when finished, will modify the UI and execute a Toast. Let's say that the user exits the Activity before the AsyncTask has finished. Can this cause problems as in Exceptions: I.e. could it happen that an UI element pointer goes null and that when the AsyncTask finishes it could cause runtime exceptions?
As it is now I've done a design where the Application class handles the AsyncTask and notifies the Activity through a BroadcastReceiver to do UI tasks if Activity still is around (i.e. more of an Observer pattern). Is this a "safer" design?
/ Henrik
I believe this does cause a problem. If the activity that created the AsyncTask is not around anymore, the an exception is thrown because the parent handler is not there anymore. The correct approach is to keep the reference of the AsyncTask in that activity, and capture onPause() event. In the pause event, I would cancel the AsyncTask and clean up if there is anything that needs to be cleaned up.
To answer your second question, it all depends on what is the requirement. If the requirement is for that task to still be around then yes you can attach the AsyncTask to the application. But it sounds like there is something that might be not correct here. You said if Activity still is around. If you don't need the task once the activity has disappeared then you might as well go with my original approach which is cancel the task and throw it away when the activity is paused.
Also, one final note. If you keep a reference to the activity around even after the activity has stopped, you will have a memory leak because that activity still has a reference that cannot be cleaned up until the task has completed.
This article sounds similar to what you are doing. If you really want to keep the task around then this seems like a good solution. I also found Android AsyncTask Context Terminated that might help you.

Message Handling, unexpected behavior with worker threads

I'm taking a stab at a large program with a background Service and I'm implementing a (rather poorly thought out) Message handling procedure using basic Handler objects. The application has a main menu with buttons which start 6 different activities.
Problem is this: if i start a worker thread which kicks off a query to the database and retrieves some data, and I close the Activity that started the aforementioned worker thread, the Handler in the Activity still tries to run and show a dialog, even though the Activity that created it is now finished (or not in focus). How can I tell whether the current Activity is in focus before committing any (UI) changes?
I ended up solving the issue by simply putting the 'showDialog()' call in a try statement, but i'd like a more sophisticated solution, as this just seems like the wrong way to do things.
Use sendBroadcast(), with the Activity registering a BroadcastReceiver for the broadcast via registerReceiver() in onResume() and unregistering it in onPause(). Then, it will only process the event if it is in the foreground.
Put some flag in onPause() method of activity that starts the thread to indicate that it is not foreground anymore. In onStart() reverse the flag.
When it is a time to display dialog, check this flag and only show dialog if activity is running.

Categories

Resources