5

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?

Chris Knight
  • 24,333
  • 24
  • 88
  • 134
  • Are you using any other AsyncTasks while this one is executing? Or is this the only AsyncTask? – Rowan Freeman Feb 24 '13 at 22:17
  • This is the first AsyncTask started by the app. I have many others, but they are called after completion of this one. – Chris Knight Feb 24 '13 at 22:22
  • What sort of Android device is this? Have you tried it on others? – Rowan Freeman Feb 24 '13 at 22:54
  • It happens on my Nexus 4, but have had the odd user report from other devices and OS versions. – Chris Knight Feb 24 '13 at 22:58
  • It's a tough one. I'm out of ideas :\ – Rowan Freeman Feb 24 '13 at 23:19
  • Try to put the code in doInBackground in a try/catch block and print the caught exception's stacktrace – stan0 Feb 25 '13 at 11:03
  • If you have an `AsyncTask` running already, a new one will fail to execute until it completes, in certain OS versions. When you say "works 99% of the time", it makes me think of a timing issue, which would certainly cause this exact behavior, if you've got a possibility of some other `AsyncTask` running already. – Todd Sjolander Mar 25 '13 at 14:53
  • Thanks @ToddSjolander. Perhaps I've got rogue AsyncTasks hanging around eating up my thread queue in unusual situations. Good food for thought anyway, so appreciate the thoghts – Chris Knight Mar 25 '13 at 22:20

1 Answers1

2

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

Community
  • 1
  • 1
type-a1pha
  • 1,891
  • 13
  • 19
  • It turns out that the core thread pool on Honeycomb+ is just 1 background thread (http://developer.android.com/reference/android/os/AsyncTask.html#execute(Params...)). I have another service running alongside my application which, under unusual circumstances, can execute an Aysnc task for a significant duration essentially hogging the single background thead. Looks like its time to redesign the thread-hogging service Asyc task. See also this super helpful question and answer on this subject: http://stackoverflow.com/questions/9654148/android-asynctask-threads-limits – Chris Knight Sep 06 '13 at 14:54