Android - Two AsyncTask running parallelly - Exception - android

I develop a mobile app where clicking on button in Activity A triggers Activity B as well an async task. In Activity B, there is a async task which gets trigerred in the oncreate method. So, there will be 2 async task which will be running parallelly. both the async task interact with the server. (POST and GET method respectively)
All is good when the server is up and running. When I make the server deliberately down and click on the button in Activity A, I am not sure where the control is going. I expect a connectiontimeout exception and I am getting it. But sometimes the async task in Activity B's exception occurs first and sometimes the async task in Activity A's exception occurs first.
In the catch block in both the async method, there is an intent which starts anotheractivity (No server Connection activity)
Once after the exception ( in both of the async methods) has occured I am not seeing any logs in the Logcat. I believe the app comes to a standstill. I wish to gracefully inform the other async task which ever is running to stop.
Could anyone please help me in accomplishing this task. Is there any good design approach to handle this? Let me know and thanks for your time and effort.

Consider implementing your own timeout detection and handling.
Use handler and provide timeout period when firing the ASyncTask
private void readFromServer(String url, int timeout) {
// read from server
final ServerHit serverHit = new ServerHit(this);//ServerHit is my asyncTask
serverHit.execute(url);
// set a timeout
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (serverHit.getStatus() == AsyncTask.Status.RUNNING)
{
serverHit.cancel(true);
}
}
}, timeout);
}
However if you call only one instance of each AsyncTask consider declare it as a static or let it follow the Singleton Pattern. And upon cancelling one task just cancel the other one.
EDIT
You can define those asyncatasks as static and can cancel them on timeout

You should read the first "Related" post on the right "Is AsyncTask really conceptually flawed or am I just missing something?".
Your attempt to do what you are doing, shows little understanding of how the Android OS manages Activities and their AsyncTasks. Trying to start one from Activity A and then start Activity B before it finishes is doomed to fail.

Related

Fragments and Threads in Android

I have a MainActivity that uses fragments.
The onCreate of MainActivity completes its onCreate with the use of
welcomeFragment = new MyWelcomeFragment();
fr.beginTransaction().replace(R.id.mainContent, welcomeFragment).commit()
As a part of MyWelcomeFragment's on onResume, a thread is started to get updates from my webserver. If the user selects an action before the thread is completed and goes to MyNewsFragment, what happens to the thread that has yet to complete running in MyWelcomeFragment's thread stack?
Thread was created with: (myThread and handler are instance variables)
myThread = new Thread(new Runnable() {
#Override
public void run() {
sendDataToServer("");
handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
onTaskDone();
}
});
}
});
myThread.start();
Dalvik keeps all Thread references in the runtime so your thread will keep running unless it is terminated or completes (some reference). So depending on where you start your thread, you may be creating more than one. There is no clean way to cancel a Thread and in this case you may need to first cancel the http request inside sendDataToServer and use a shared flag to stop the thread.
In a bigger picture, I would suggest
move the networking method to Activity and handle it there since it has longer lifespan than
Fragment
use Android Volley to handle networking. With it you can manage inadvertent multiple requests to send data to your server. Since each request can be attached with tag, you can cancel any with a particular tag in the queue (in your case the one corresponding to sendDataToServer process) before starting a new one.
and finally use Publisher-Subsriber pattern which has already been made available by libraries like Otto or EventBus. This allows communication between Fragments or Activities while avoiding life cycle related problems. In a gist: a publisher emits events to subscribers registered to it and unlike listeners both publisher and subscriber are totally decoupled. In your case, when sendDataToServer completes, you will not know if the fragment containing onTaskDone is still around. If this method manipulates UI while the fragment has destroyed its view then you will definitely get an error. So onTaskDone should be wrapped inside a subscriber method whose parent fragment is registered to the http event publisher and deregistered as soon as its view is destroyed.
It'll keep running until run() method completes, which is probably for how long it takes for sendDataToServer("") takes to complete, as the handler should be fairly quick in comparison to network IO - or the thread is force interrupted.
Are you still interested in the result if the user switches fragments?
Are you keeping a reference to the welcome fragment? (Via either fragment manager or activity) - if so you could still access the result.
If the user goes back to welcome fragment, the previous thread reference will be lost.
Thread will keep on running till MyWelcomeFragment is alive and If you don't kill it in onPause().

What can cause a AsyncTask not to execute?

I have a very sporadic failure in my app I'm trying to resolve. On entry to the app, at one point the main UI thread processing ends and passes control to a background thread to retrieve some data. When the data is retrieved, control passes back to the main UI thread to process it for display. However, on some rare occassions (it works 99% of the time), the AsyncTask seems to be failing to be called leaving the app in a poor static state forever waiting for the AsyncTask to complete.
Here's a snapshot of the code in the Activity:
//method call from main UI thread
private void fetchSomeData() {
Log.d("myTag", "In fecthSomeData()");
new ReadFileAsyncTask<DataModel>().execute(this);
}
Here's the ReadFileAsyncTask implementation:
public class ReadFileAsyncTask<A> extends AsyncTask<I_ReadFileListener<A>, Void, A>
{
I_ReadFileListener<A> listener;
#Override
#SuppressWarnings("unchecked")
protected A doInBackground(I_ReadFileListener<A>... params)
{
listener = params[0];
Log.d("mytag", "BACKGROUND: Loading " + listener.getFilename() + " from disk");
A fileContents = (A) FileUtils.readDataFromInternalStorage(listener.getContext(), listener.getFilename());
return fileContents;
}
#Override
protected void onPostExecute(A result)
{
Log.d("myTag", "FOREGROUND: Executing onFileRetrieved listener");
listener.onFileRetrieved(result);
}
}
Capturing the logs on this rare failure yeilds:
In fetchSomeData()
...
(Other log messages from other interactions with the activity such as menu creation and navigation initialization)
but, crucially, not the log statement from the second line of code in the doInBackground method. One thought I had was that this log statement was failing, but I'm not seeing any force stop messages, error in my logs or ACRA crash reports. The application is still active (I can navigate to other activities and back) so I'm at a loss as to what might stop this background thread from running properly. Any ideas?
Sadly AsyncTask is not suitable for critical code execution since, depending on the ThreadPool base and max size, your AsyncTask may never execute.
Moreover, the onPostExecute method could be called when the Activity it is referring (i.e. its creating context) has already been destroyed. You have no way to synchronize with it rather then maybe using join() on the AsyncThread from the UI Thread.
Even though I've seen doing this also in the Android Camera App it isn't a good idea to block the UI Thread waiting for an event since you coulg get an ANR (Application Not Running) notification.
Take a look at this: Is AsyncTask really conceptually flawed or am I just missing something?
Consider using IntentServices, HandlerThread or ThreadPoolExecutors if you need a possibly better way to synchronize your worker thread with your your UIThread.
From http://developer.android.com/training/run-background-service/create-service.html:
Also, an IntentService isn't affected by most user interface lifecycle events, so it continues to run in circumstances that would shut down an AsyncTask

Mono Android: terminate thread in onPause() state

I am running into a strange problem...
My application is meant to do some webservice calls on a separate thread. Once the webservice call is finished, it would navigate user to a different activity.
In the case when user press the home button or exit current activity it should terminate the webservice if the webservice call thread is still running. Hence I put a thread termination method in the OnPause state.
Here is the method block that is running inside the thread:
private Thread _webserviceThread;
void WebserviceCallThread(){
WebRestult result= WebserviceCall();
if(!result.containsError()){
RunOnUIThread(delegate{
transitionToActivityXYZ();
});
}
}
void RunThreadAction(){
_webserviceThread = new Thread(new ThreadStart(WebserviceCallThread));
_webserviceThread.Start();
}
protected override void OnPause(){
if(_webserviceThread != null && _webserviceThread.IsAlive){
_webserviceThread.Abort();
}
}
After the webservice call is done and begin the transition to another page, It gets to the OnPause state. However, in some strange cases, it would think that the thread is not finished in the OnPause state, even though the activity transition is the last line of the method.
Has anyone ran into this problem before? If so, how did you solve this problem?
Thanks!
I always use AsyncTask for this kind of thing. Not only does it abstract away the explicit thread handling and provide hooks to do everything you want here; it's also a nice way to represent a unit of work that can be used from other activities.
There's a simple example in this post part way down, but it doesn't use the generic parameters which are quite handy.
Why not use Task Parallel Library,
It is standard .NET, and with AsyncTask, it is only recommended for tasks that take less than few seconds. see the Documentation
AsyncTasks should ideally be used for short operations (a few seconds
at the most.) If you need to keep threads running for long periods of
time, it is highly recommended you use the various APIs provided by
the java.util.concurrent
Below is an example for how to use Task Parallel Library, taken from here
private void loginWithTaskLibrary()
{
_progressDialog.Show();
Task.Factory
.StartNew(() =>
_loginService.Login("greg")
)
.ContinueWith(task =>
RunOnUiThread(() =>
onSuccessfulLogin()
)
);
}

How to cancel Service/IntentService/AsyncTask/Looper

I'm going nuts here.
I want a simple thing - I have a long task (fetching several data objects from the web) and I want the ability to cancel it.
I tried a lot of things (a lot) and nothing works
The flow goes like this:
the user click on a button
I start the work (I tried with AsyncTask, Service, IntentService and Looper)
the task takes care of everything including adding ongoing notification for progress updates
the intent in the notification has a call for a new activity that her only purpose is to cancel the ongoing task
in the cancelActivity I tried to call stopService() for Service/IntentService or do
Looper.quit() for the Looper (I don't remember what I tried for AsyncTask, not sure if there is such api for canceling it)
In my point of view the best option will be using IntentService (I could have several task lining up and IntetService will do it in order like I want) but
I'm open to suggestions for any type of implementation - I don't care what the code will be, just that I will have the option to cancel the task
Thank you in advance for your help
Dror
(I'm off to bed - 8 hours on the same issue is just too much)
It does not matter what specific operation you use to stop the task if you don't recognize the stop condition in your background logic. The only way to cleanly accomplish it is if background worker stops and exits in good faith.
There are few possible scenarios and solutions that you can use for canceling background work.
Background thread executes many short steps (for example computation with some loops). In this case, check some flag (could be isInterrupted()) between operations and exit if this flag indicates that operation must stop.
Background thread is waiting on monitor. Call interrupt() on background thread, catch exception in in exception handler make appropriate steps to finish this task cleanly and exit.
Background thread is waiting on IO. This use case is very hard to solve in general case. If you use some socket, you can try closing this socket externally and catch the exception. In worst case scenario, you can just abandon the thread in the state that if it ever returns from IO it knows that it is canceled and IO results must be discarded. If you do it often - you will run out of memory, so I would not really recommend it.
In any case, there is no way (except killing the thread which is really bad) to stop your task if it does not know about possibility of being stopped.
Ok, i manged to do something close to what I want.
I'm using IntentService that will queue my task. each new task is AsyncTask. the AsyncTask starts with sending notification with pendingIntent for cancelActivity.
When clicking on the notification the user gets a warning popup about stopping the task. If he clicks yes than I do stopService() on my IntentService.
In the IntentService I added:
#Override
public void onDestroy() {
currentTask.cancel(true);
if (mNotificationHelper != null)
mNotificationHelper.completed();
super.onDestroy();
stopSelf();
}
in the AsyncTask I added:
#Override
protected void onCancelled() {
isCanclled = true;
httpClient.getConnectionManager().shutdown();
mNotificationHelper.completed();
if (mAsyncTaskListener != null)
mAsyncTaskListener.AsyncTaskCanceled();
}
so that will drop all the connection currently in motion. In the actual code that do the work I need to catch the exception for connection shutdown and handle it
so in the end I'm not actually stopping the AsyncTask/Service but rather exposing the httpClient so I will be able to drop the connection in asynchrony why.
I think is a bit ugly but I got no other way
thank you all

Running same background task from two activities

In my app I have a background task (using AsyncTask) that downloads stuff from a web site.
This task can be called from two separate activities, and it is possible to call it twice. So in "activity1" the background task "update" is called, and runs for a while (it takes something like 5-10 seconds usually).
Then while it's running, user switches to "activity2" and runs "update" again.
This gives problems: either a crash when both try to clear the database (command: DELETE FROM table) at the same time, causing a "database locked" error. Or they try to put the same item in the database causing a duplicate.
I've tried to solve this by setting a static boolean flag to true when a task is active.
When the task is called, it will check for this flag, and if true (i.e. the same task running on another thread) it goes into a wait loop using a handler until this flag clears, and then returns. This to make sure that when the background task returns, the update has been done. I have to use a Looper for that: this sometimes fails with an error "can create only one looper per thread". And I really have it in a way that only one looper can be started, this is the offending code, which appears at the start of the background task:
if (active) {
Looper.prepare();
handler = new Handler();
handler.postDelayed(new Runnable() {
int count = 0;
#Override
public void run() {
if (active) {
count++;
if (count < 1000)
handler.postDelayed(this, 100);
}
}
}, 100);
Looper.loop();
active = false;
return "done";
}
And to make matters worse it often seems to hang in this loop, without returning.
How to solve such a situation?
Why don't use synchronization instead? It sounds like a concurrency issue. Why don't you make sure that if the first background task is running then the second background task is sleeping until the first one is finished.
Or ensure somehow, that if the user switches to Activity number 2, the background task from activity number 1 is cancelled.
Instead of the AsyncTask you can consider to use IntentService. Have a look at the Android Service concept. The IntentService class ensures that only one request will be processed at one time.
I found this answer very useful during implementing IntentService with Activity callback communication.
Database locking issues solved by wrapping it into a ContentProvider. Besides problems with a method being called again before the previous instance was finished, I had the issue of different methods running in different background threads clashing while trying to write to the database.
Officially designed to allow for sharing data between apps, it also works great for sharing data between threads in a single app. The ContentProvider will make sure that no locking issues occur.

Categories

Resources