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

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

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

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

Я воссоздаю ImageActivity и задачу, нажимая кнопку «Назад», а затем нажимая кнопку на MainActivity.

Любые идеи? Я действительно борюсь с этим.

ОБНОВЛЕНИЕ: код, который запускает 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);
    }
}

ОБНОВИТЬ:

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


person Vidar Vestnes    schedule 02.11.2010    source источник
comment
Разместите свой код. Как ты это называешь. Мы понятия не имеем, как помочь вам без кода   -  person Falmarri    schedule 02.11.2010
comment
Имея точно такую ​​​​же проблему, после запуска нескольких AsyncTasks в моем приложении приложение выполняется только до onPreExecute(), но не входит в doInBackground(). Попробуйте ваш подход к теме сейчас.   -  person Mathias Conradt    schedule 20.11.2011
comment
Я с той же проблемой. Странно то, что он варьируется от устройства к устройству. Это происходит на планшете (Android 4.0), но на телефоне (Android 2.3.4) с точно таким же кодом его нет.   -  person Hong    schedule 07.07.2012
comment
в моем случае doInBackground работает, а Log.d() внутри не работает!   -  person Ali Shakiba    schedule 10.10.2012


Ответы (7)


Удаление 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();
    }
}
person Vidar Vestnes    schedule 03.11.2010
comment
Спасибо, у меня такая же проблема (некоторое время назад разместил ее здесь, на SO, и это не решило проблему), поиск в Google привел меня сюда :) - person Ryan; 29.09.2011
comment
Это проливает свет на то, почему AsyncTask мог подвести вас (и меня!): foo.jasonhudgins.com/2010/05/limitations-of-asynctask.html - person Archie1986; 05.12.2011
comment
Просто поделился мыслью, недавно я столкнулся с чем-то похожим на вуду в поведении AsyncTask. Однако я преодолел это после закрытия уже работающего AsyncTask в фоновом режиме. Странно, но это сработало для меня. - person faizanjehangir; 04.04.2014
comment
В моем ответе излагается конкретная причина отказа. stackoverflow.com/a/20620623/9636 - person Heath Borders; 24.07.2014

Я столкнулся с похожей проблемой. Вы не можете запускать несколько асинтасков параллельно до SDK 11. Проверьте здесь для получения дополнительной информации

person ericwjr    schedule 03.02.2013

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

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

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

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

person Heath Borders    schedule 16.12.2013
comment
doInBackground() не должен вызывать методы пользовательского интерфейса (например, для всплывающего диалогового окна, как вы упомянули). - person Andrew Mackenzie; 27.03.2014
comment
Я показал диалог в основном потоке, но он был вызван doInBackground. - person Heath Borders; 27.03.2014
comment
Это правильный ответ, который следует принять. (Только что закончил собственное расследование по теме и пришел к такому же выводу - отдельный Исполнитель) - person Alexander Malakhov; 24.07.2014
comment
Итак, если я правильно читаю эту документацию, они перешли от последовательного выполнения к параллельному выполнению и обратно к последовательному выполнению? И теперь, если нам нужно одновременно выполнить две или более AsyncTasks, нам нужно использовать несколько исполнителей, каждый из которых работает в своем собственном потоке? - person Joshua Pinter; 01.08.2017
comment
Да, или использовать один параллельный исполнитель. - person Heath Borders; 02.08.2017

Используйте 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);

        }
  }
person DustinB    schedule 21.09.2012

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

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

person Octavian A. Damiean    schedule 02.11.2010
comment
Метод downloadBitmap немного длинный, и это не проблема. У меня возникает та же проблема, если я пытаюсь использовать Thread.sleep(5000), имитирующий медленную загрузку. Когда я использую Thread.sleep, я могу запускать ImageActivity 3-4 раза, и задача работает. После этого задача печатает только onPreExecute, а не сообщение журнала doInBackground, что означает, что по какой-то причине она никогда не вызывается. И да, я пробовал не отменять задачу, но мне это не помогло. - person Vidar Vestnes; 03.11.2010
comment
Есть ли еще код, который вы пропустили? - person Octavian A. Damiean; 03.11.2010

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

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

person habib    schedule 13.04.2012

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

person Alex    schedule 02.03.2013