Pergunta

This question already has an answer here:

I'm having a problem with the AsyncTask class. It seems like my task stops working after creating 4 or 5 tasks.

Im having 2 activities. MainActivity which only holds a button that starts a second activity called ImageActivity.

ImageActivity is very simple. it got an onCreate that sets the layout, and then it starts a new AsyncTask that loads an image from the internet. This works fine the first few times. But than it suddenly stops working. The onPreExecute method is run every time, but not the doInBackground method. I have tried to simplify the doInBackground with a sleeping loop, and the same thing happens. I cant understand this behavour since the asynctask is both canceled and set to null in the onDestroy method. So every time i start a new ImageActivity, i also create a fresh AsyncTask.

I recreate the ImageActivity and the task by hitting the back button, and than clicking the button on the MainActivity.

Any ideas anyone? I'm really struggling with this one.

UPDATE: Code that starts the ImageActivity (inside a button onClickListener)

Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.setClassName(this, ImageActivity.class.getName());
startActivity(intent);

The code above starts this activity

    public class ImageActivity extends Activity {

    private AsyncTask<Void, Void, Void> task;

    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.main);

        task = new AsyncTask<Void, Void, Void>() {

            @Override
            protected void onPreExecute()
            {
                Log.d(TAG, "onPreExecute()");
            }

            @Override
            protected Void doInBackground(Void... params)
            {
                Log.d(TAG, "doInBackground() -- Here is the download");
                // downloadBitmap("http://mydomain.com/image.jpg")
                return null;
            }

            @Override
            protected void onPostExecute(Void res)
            {
                Log.d(TAG, "onPostExecute()");
                if(isCancelled()){
                    return;
                }
            }
        }.execute();
    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        task.cancel(true);
    }
}

UPDATE:

I have tested using a combination of traditional Threads and runOnUiThread method, and it seems to work better. Now the thread runs every time.

Foi útil?

Solução

Removing the AsyncTask and using a traditional Thread instead of combining it with runOnUiThread seems to work. But I still have not found the reason why the AsyncTask is so "unstable".

Here is the code that works for me:

public class ImageActivity extends Activity {

    private Thread worker;

    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.main);

        worker = new Thread(new Runnable(){

            private void updateUI(final List<Object> list)
            {
                if(worker.isInterrupted()){
                    return;
                }
                runOnUiThread(new Runnable(){

                    @Override
                    public void run()
                    {
                        // Update view and remove loading spinner etc...
                    }
                });
            }

            private List<Object> download()
            {
                // Simulate download
                SystemClock.sleep(1000);
                return new ArrayList<Object>();
            }

            @Override
            public void run()
            {
                Log.d(TAG, "Thread run()");
                updateUI(download());
            }

        });
        worker.start(); }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        worker.interrupt();
    }
}

Outras dicas

I ran into similar problem. You can't have multiple Asynctasks running in parallel up until SDK 11. Check here for more info

I just ran into this problem as well. If you use AsyncTask.execute, your task is run on a serial queue (from the Android 4.3 source):

When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.

This is consistent with behavior that I saw. I had an AsyncTask popped up a dialog in doInBackground and blocked until the dialog was closed. The dialog needed its own AsyncTask to complete. The dialog's AsyncTask.doInBackground method never executed because the original AsyncTask was still blocked.

The solution is to execute the second AsyncTask in a separate Executor.

Use traceview to investigate -- or obtain a thread dump. My guess is that one of your AsyncTask threads are hanging on downloading.

AsyncTask has a small thread pool, so if one of your tasks hangs, it could end up blocking your thread pool.

Here's a quick test you can run -- on 4.3, I see that I have only 5 concurrent threads I can run. When one thread exits, other threads start up.

  private void testAsyncTasks() {

        for (int i = 1; i <= 10; i++) {
              final int tid = i;
              new AsyncTask<Integer, Void, Void>() {
                    protected void onPreExecute() {
                          Log.d("ASYNCTASK", "Pre execute for task : " + tid);
                    };

                    @Override
                    protected Void doInBackground(Integer... args) {
                          int taskid = args[0];
                          long started = SystemClock.elapsedRealtime();
                          Log.d("ASYNCTASK", "Executing task: " + taskid + " at " + started);
                          for (int j = 1; j <= 20; j++) {
                                Log.d("ASYNCTASK", "   task " + taskid + ", time=" + (SystemClock.elapsedRealtime() - started));
                                SystemClock.sleep(1000);
                          }
                          return null;
                    }

                    protected void onPostExecute(Void result) {
                          Log.d("ASYNCTASK", "Post execute for task : " + tid);
                    };
              }.execute(i);

        }
  }

You shouldn't have to worry about housekeeping thread in Android as it is managed by the system.

Please also post the image download method. Have you also tried to not cancel the thread in the onDestroy() method? How are you returning the the image to your UI thread?

The problem I believe is with the heavy image download task. Even if you cancel the async task the image download will continue to execute and the async task does not finish until the download is complete. You might want to check the isCancelled() method on AyncTask while the download is going on and kill the download if the task is cancelled.

For reference, heres the documentation on cancel() method : Attempts to cancel execution of this task. This attempt will fail if the task has already completed, already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task. Calling this method will result in onCancelled(Object) being invoked on the UI thread after doInBackground(Object[]) returns. Calling this method guarantees that onPostExecute(Object) is never invoked. After invoking this method, you should check the value returned by isCancelled() periodically from doInBackground(Object[]) to finish the task as early as possible.

I had this too, no real reason for not starting. I've noticed that after restarting adb it worked again. Not sure why this is, but it did work for me

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top