AsyncTask doInBackground не запускается

У меня проблема с классом AsyncTask. Кажется, моя задача перестает работать после создания 4 или 5 задач.

Im имеет 2 действия. MainActivity, которая содержит только кнопку, которая запускает второе действие под названием ImageActivity.

ImageActivity очень прост. он получил onCreate, который устанавливает макет, а затем он запускает новую AsyncTask, которая загружает изображение из Интернета. Это работает отлично несколько раз. Но он внезапно перестает работать. Метод onPreExecute запускается каждый раз, но не метод doInBackground. Я попытался упростить doInBackground со спящим циклом, и то же самое происходит. Я не могу понять это поведение, поскольку asynctask отменяется и устанавливается в null в методе onDestroy. Поэтому каждый раз, когда я запускаю новую ImageActivity, я также создаю новую AsyncTask.

Я воссоздал ImageActivity и задачу, нажав кнопку "Назад", а затем нажав кнопку "MainActivity".

Какие-нибудь идеи? Я действительно борюсь с этим.

UPDATE: код, запускающий ImageActivity (внутри кнопки onClickListener)

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

Приведенный выше код запускает эту операцию.

    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:

Я тестировал, используя комбинацию традиционных Threads и runOnUiThread, и, похоже, он работает лучше. Теперь поток запускается каждый раз.

Ответ 1

Сбой использования AsyncTask и использование традиционного потока вместо объединения его с runOnUiThread. Но я до сих пор не нашел причины, почему AsyncTask настолько "нестабилен".

Вот код, который работает для меня:

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();
    }
}

Ответ 3

Я просто столкнулся с этой проблемой. Если вы используете AsyncTask.execute, ваша задача запускается в последовательной очереди (из источника Android 4.3):

При первом вводе AsyncTasks выполнялись последовательно на одном фоновый поток. Начиная с DONUT, это было изменено на пул потоки, позволяющие нескольким задачам работать параллельно. Начиная с HONEYCOMB, задачи выполняются в одном потоке, чтобы избежать ошибки приложения, вызванные параллельным выполнением.

Это соответствует поведению, которое я видел. У меня было AsyncTask появилось диалоговое окно в doInBackground и заблокировано, пока диалог не был закрыт. Для завершения диалогового окна был необходим свой AsyncTask. Диалог AsyncTask.doInBackground никогда не выполнялся, потому что исходный AsyncTask был по-прежнему заблокирован.

Решение состоит в том, чтобы выполнить второй AsyncTask в отдельном Executor.

Ответ 4

Используйте traceview для исследования - или получите дамп потока. Я предполагаю, что один из ваших потоков AsyncTask зависает при загрузке.

AsyncTask имеет небольшой пул потоков, поэтому, если одна из ваших задач зависает, это может привести к блокировке пула потоков.

Вот быстрый тест, который вы можете запустить - в 4.3, я вижу, что у меня есть только 5 одновременных потоков, которые я могу запустить. Когда один поток выходит, запускаются другие потоки.

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

        }
  }

Ответ 5

Вам не нужно беспокоиться о домашней нищете в Android, поскольку она управляется системой.

Также отправьте способ загрузки изображения. Вы также пытались не отменить нить в методе onDestroy()? Как вы возвращаете изображение в поток пользовательского интерфейса?

Ответ 6

Проблема, которую я считаю, связана с задачей загрузки тяжелых изображений. Даже если вы отмените асинхронную задачу, загрузка изображения продолжит выполнение, и задача async не завершится до завершения загрузки. Вы можете проверить метод isCancelled() на AyncTask во время загрузки и убить загрузку, если задача отменена.

Для справки, существует документация по методу cancel(): Попытка отменить выполнение этой задачи. Эта попытка потерпит неудачу, если задача уже завершена, уже отменена или не может быть отменена по какой-либо другой причине. В случае успеха, и эта задача не началась при вызове отмены, эта задача никогда не должна запускаться. Если задача уже запущена, параметр mayInterruptIfRunning определяет, должен ли поток, выполняющий эту задачу, прерваться при попытке остановить задачу. Вызов этого метода приведет к вызову onCancelled (Object) в потоке пользовательского интерфейса после возврата doInBackground (Object []). Вызов этого метода гарантирует, что onPostExecute (Object) никогда не вызывается. После вызова этого метода вы должны периодически проверять значение, возвращаемое isCancelled(), из doInBackground (Object []), чтобы закончить задачу как можно раньше.

Ответ 7

У меня тоже было это, никакой реальной причины для того, чтобы не начать. Я заметил, что после перезагрузки adb он снова работал. Не знаю, почему это так, но это сработало для меня.