AsyncTask, вызванный из Handler, не выполнит doInBackground

Приложение, над которым я работаю, использует фоновый поток для загрузки списка изображений через API, а затем отображает изображения в слайд-шоу.

Существует фоновое задание (в настоящее время AsyncTask) для периодической выборки новых изображений.

Я не получаю сообщений об ошибках о неправильном Thread и т.д., это просто, что второй экземпляр AsyncTasks не будет запускать метод doInBackground.

Вот код из Activity:

private DownloadTask mDownloadTask = null;
private Handler mHandler;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if(mDownloadTask != null) {
                mDownloadTask.cancel(true);
            }
            mDownloadTask = new DownloadTask();
            mDownloadTask.execute((Void[]) null);
        }
    };

    mDownloadTask = new DownloadTask();
    mDownloadTask.execute((Void[]) null);
}

DownloadTask выглядит следующим образом:

@Override
protected List<String> doInBackground(Void... voids) {
     // Download list of URLs from server, etc.
}

@Override
protected void onPostExecute(List<String> urls) {
    mHandler.sendEmptyMessageDelayed(111, 5000);
}

Будет вызываться обработчик, будет вызываться onPreExecute (в AsyncTask) и начальный запуск DownloadTask (прямо в onCreate).

В соответствии с этим вопросом: Android SDK AsyncTask doInBackground не работает (подкласс), это может быть связано с SDK15.

Спасибо за любые подсказки.


Обновить. Когда я получил комментарии о том, что обработчик может не быть в потоке пользовательского интерфейса (что является странным, поскольку Thread.currentThread является таким же как в методе onCreate, так и в методах Handlers handleMessage, я переработал метод handleMessage для:

mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if(mDownloadTask != null) {
                    mDownloadTask.cancel(true);
                }
                mDownloadTask = new DownloadTask();
                mDownloadTask.execute((Void[]) null);
            }
        });
    }
};

Все еще без успеха.


Обновить полный класс DownloadTask

class DownloadTask extends AsyncTask<Void, Void, List<String>> {

    @Override
    protected void onPreExecute() {
        // Cancel the animation.
        if (mSlideshowAnimation != null) {
            mSlideshowAnimation.cancel(true);
        }

        mImageView1.setVisibility(View.GONE);
        mImageView2.setVisibility(View.GONE);
        animate(mProgressBar).alpha(1.0f).setDuration(500).start();

        Log.d(TAG, "Download preparation done.");
    }

    @Override
    protected List<String> doInBackground(Void... voids) {
        Log.d(TAG, "Download");
        SharedPreferences s = getSharedPreferences("access", Context.MODE_PRIVATE);
        String token = s.getString("token", null);

        Log.d(TAG, "Downloading slideshows.");

        List<String> urls = new ArrayList<String>();
        Slideshow[] slideshows = new Api(SlideshowActivity.this).getSlideshows(token);
        for (Slideshow slideshow : slideshows) {
            urls.addAll(slideshow.getAllPhotoUrls());
        }

        Log.d(TAG, "Downloading slideshows: " + slideshows.length);

        for (String url : urls) {
            try {
                url = Api.HOST + url;

                if (!Cache.fileExists(Cache.getCacheFilenameForUrl(SlideshowActivity.this, url))) {
                    Cache.cacheStream(SlideshowActivity.this, HttpHelper.download(SlideshowActivity.this, url), url);
                } else {
                    Log.d(TAG, "Cached: " + url);
                }
            } catch (IOException e) {
                Log.e(TAG, "Error while downloading.", e);
            }
        }

        Log.d(TAG, "Downloading slideshows finished.");

        return urls;
    }

    @Override
    protected void onPostExecute(List<String> urls) {
        Log.d(TAG, "download successful");
        animate(mProgressBar).alpha(0.0f).setDuration(500).start();

        mCurrentImageIndex = -1;
        mImageUrls = urls;

        mSlideshowAnimation = new SlideshowAnimation();
        mSlideshowAnimation.execute((Void[]) null);

        mHandler.sendEmptyMessageDelayed(111, 5000);
    }
}

Ответ 1

Благодаря полезной дискуссии с Вакасом (спасибо!), я наконец обнаружил ошибку в моем коде. На самом деле все написанное выше верно и работает как есть. Проблема с моим делом заключалась в том, что вторая задача заблокировала первую и наоборот.

Возможно, совпадение было найти это сообщение в группах Google: http://groups.google.com/group/android-developers/browse_thread/thread/f0cd114c57ceefe3?tvc=2&q=AsyncTask+in+Android+4.0. Порекомендуйте, чтобы все участники потоковой передачи внимательно изучали это обсуждение.

AsyncTask переключила модель Threading на последовательный исполнитель (снова), который несовместим с моим подходом, имеющим 2 AsyncTasks.

Наконец, я переключил обработку "Загрузка" на классический Thread и использовал Handler для отправки сообщений, чтобы отменить Слайд-шоу, если это необходимо. Использование обработчиков sendEmptyMessageDelayed Я просто заново заново создаю "Загружать поток", чтобы обновить данные.

Благодаря всем комментариям и ответам.

Ответ 2

Handler - это своего рода поток в android, а AsyncTask также работает в разных потоках. Когда вы используете AsyncTask, существует несколько правил.

Существует несколько правил потоковой передачи, которые должны соблюдаться для этого класса для правильной работы:

Экземпляр задачи должен быть создан в потоке пользовательского интерфейса. выполнение (Params...) должен быть вызван в потоке пользовательского интерфейса. Не вызывайте onPreExecute(), onPostExecute (Результат), doInBackground (Params...), onProgressUpdate (Прогресс...) вручную. Задача может быть выполнена только один раз (исключение будет выбрано при попытке выполнить второе выполнение).

Итак, ясно сказано, что AsyncTAsk должен быть вызван из потока пользовательского интерфейса.. где, как вы его называете, от Handler, который не является потоком пользовательского интерфейса...

попробуйте это тоже

mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if(mDownloadTask != null) {
                mDownloadTask.cancel(true);
            }
           if([isCancelled()][1]){
            mDownloadTask = new DownloadTask();
            mDownloadTask.execute((Void[]) null);
          } // i assume your task is not getting cancelled before starting it again..
        }
    });
  }
};

а также документация говорит об этом.

Для обработчика используются два основных вида использования:

(1) для планирования сообщений и исполняемых файлов, которые должны выполняться как некоторая точка в будущем; и (2) вставить в действие действие, выполняемое на другой поток, чем ваш собственный.