Android runOnUiThread / AsyncTask не может разрешить CalledFromWrongThreadException

Я работаю над Android-приложением и реализую ProgressBar с помощью класса AsyncTask.

Проблема в том, что на некоторых устройствах это вызывает «CalledFromWrongThreadException: только исходный поток, создавший иерархию представлений, может коснуться его представлений». В onPostExecute. На этих устройствах проблема возникает на 100%. На других устройствах он работает нормально.

public final class MyAsyncTask extends AsyncTask<String, Integer, String> { private ProgressBar progress; private ListActivity activity; public MyAsyncTask(ListActivity activity, ProgressBar progress) { this.progress = progress; this.activity = activity; } protected void onPreExecute() { this.progress.setVisibility(view.VISIBLE); } protected String doInBackground(String[] arg0) { // getting xml via httpClient return string; } protected void onPostExecute(String result) { this.progress.setVisibility(view.GONE); } 

Я не понимаю, почему onPostExecute не запускается в потоке пользовательского интерфейса, на этих определенных устройствах.

Затем я попытался вызвать его с помощью runOnUiThread, чтобы убедиться, что он работает в потоке пользовательского интерфейса.

 runOnUiThread(new Runnable() { @Override public void run() { ProgressBar progress = (ProgressBar)findViewById(R.id.some_view_progressbar); MyAsyncTask task = new MyAsyncTask(activity, progress); task.execute(); } } ); 

Даже это не решило проблему. Такое же исключение все еще происходит.

Из журнала я подтвердил, что Thread.currentThread (). GetId (), безусловно, отличается от потока основного действия приложения внутри обработчика.

Я застрял. Любые советы будут оценены.

ПРИМЕЧАНИЕ. Я редактировал пример кода (а не настоящий код) выше, чтобы исправить неправильное имя метода и отсутствие «строки возврата». Я добавлю дополнительную информацию позже.

Я не вижу ничего плохого в самой MyAsyncTask , но есть и другие вещи, которые могут пойти не так.

Запуск AsyncTask

Из Android-документов

Правила потоковой передачи

Для правильного функционирования этого класса необходимо соблюдать несколько правил потоковой передачи:

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

Вы не показываете, где вы обычно создаете экземпляр, и выполняете задачу, поэтому убедитесь, что вы делаете это в коде, который уже находится в пользовательском интерфейсе / главном потоке. Обратите внимание, что первая точка с маркером может объяснить, почему это работает для вас на некоторых устройствах, а не на других.

Создание иерархии представления

Сообщение сообщает вам

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

И вы предполагаете, что это связано с тем, что ваша асинхронная задача (странно) пытается изменить пользовательский интерфейс в фоновом потоке. Однако возможно, что вы получите эту ошибку, поскольку задача async изменяет пользовательский интерфейс в основном потоке, но интерфейс ( ProgressBar ) не был создан правильно в первую очередь.

См. Этот вопрос для примера того, как вы можете ошибочно создать представление о неправильном потоке (ничего, кроме основного потока), и получить эту же ошибку.

Больше

Однако я хотел бы видеть, где именно вы регистрируете идентификатор потока и какие значения вы получаете. Если вы проверите мои первые два предложения, и они не решают вашу проблему, нам может понадобиться дополнительная информация.

Вы также упоминаете обработчик (?), Но не показываете, как и где вы его используете. Обычно использование AsyncTask устраняет необходимость использования Handler , поэтому я немного беспокоюсь о том, как вы можете это использовать.

Обновить

Для обсуждения в комментариях ниже, похоже, проблема здесь такова, что обсуждался в этом вопросе . Некоторый код, вероятно, работает в фоновом потоке, сначала вызывает AsyncTask класса AsyncTask . Первоначальная реализация (до Jelly Bean) AsyncTask потребовала, чтобы загрузка класса происходила в основном потоке (как указано в Правилах Threading выше). Простым обходным путем является добавление кода в основной поток (например, в Application#onCreate() ), который заставляет раннюю детерминированную загрузку класса AsyncTask :

 Class.forName("android.os.AsyncTask"); 

Убедитесь, что вы вызываете aysnctask.execute () только из основного потока.

Напишите обработчик в потоке пользовательского интерфейса и вызовите обработчик из onPostExecute. Это решит проблему.

Что-то вроде этого. Имейте обработчик в потоке пользовательского интерфейса (основной поток):

 handler = new Handler(){ @Override public void handleMessage(Message msg) { //run on UI Thread } }; 

И вызовите onPostExecute () следующим образом:

  handler.sendEmptyMessage(MSG);