Я использую AsyncTask для загрузки базы данных с progressdialog, который показывает прогресс в пользовательском интерфейсе. Некоторые из моих пользователей получают ошибку:
CalledFromWrongThreadException: только исходный поток, создавший иерархию представлений, может коснуться его представлений.
Насколько я понимаю, это должно произойти только в том случае, если вы пытаетесь обновить Views от потока пользовательского интерфейса. Вот ошибка:
Com … updateops.DbCreate.onProgressUpdate (DbCreate.java:70) at com … updateops.DbCreate.onProgressUpdate (DbCreate.java:1)
И вот мой код:
public class DbCreate extends AsyncTask<String, String, String>{ private static Context mCtx; private static ProgressDialog mDialog; public static AmazonSimpleDBClient mSDbClient; public static AmazonS3Client mS3Client; private static int mAppVersion; private static boolean mCreate; public DbCreate(Context ctx, int versionCode, boolean create) { mCtx = ctx.getApplicationContext(); mAppVersion = versionCode; mDialog = new ProgressDialog(ctx); mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mDialog.setMessage("Checking for server access. Please wait..."); mDialog.setCancelable(false); mDialog.setMax(1); mDialog.show(); mCreate = create; } protected void onProgressUpdate(String... name) { if (name[0].equals("item")) { mDialog.incrementProgressBy(1); } else if (name[0].equals("setMax")) { mDialog.setProgress(0); mDialog.setMax(Integer.parseInt(name[1])); <-- This is line 70 }} @Override protected String doInBackground(String... arg0) { **do stuff** publishProgress("setMax", ""+ 3); }
Мне кажется, что я точно следую тому, что должен сделать, чтобы избежать этой ошибки. Кто-нибудь знает, почему это происходит?
Изменить: Следует также упомянуть, что этот код работает большую часть времени. Я получаю отчеты о сбоях в консоли разработчика.
В соответствии с onProgressUpdate (Прогресс …) вызывается в потоке пользовательского интерфейса после вызова publishProgress (Прогресс …).
Вы должны проанализировать весь отчет журнала, чтобы проверить, есть ли вероятность, что ваша задача async была создана в другом потоке .
И если вы действительно не можете найти основную причину, вы можете использовать обработчик, созданный в потоке пользовательского интерфейса, для обхода.
Вы правильно выглядите, и в большинстве случаев он должен работать. Я предлагаю вам использовать обработчик. Вы можете написать обработчик в потоке пользовательского интерфейса и вызвать его из onProgressUpdate (). Это полностью обеспечит выполнение работы пользовательского интерфейса в потоке пользовательского интерфейса.
Это точно определит вашу проблему, но я не знаю, почему вы получаете ошибку gettin из первых рук. Я видел этот вопрос раньше и не получил конкретной причины для этого.
У меня была та же проблема, которую вы описываете, и я исправил ее с помощью runOnUiThread()
с контекстом, принадлежащим AsyncTask (как и в вашем примере).
Следующее решение должно освободить ваши проблемы;
@Override protected void onProgressUpdate(final String... messages){ myActivityReference.runOnUiThread(new Runnable() { @Override public void run() { // Your UI changes here. } }); }
Стоит отметить, что мой AsyncTask
изначально вызывался из AlertDialog
, и это, по моему мнению, вызывает проблему.
Я нашел ту же проблему на устройствах Android 2.3.x и вот журнал сбоев:
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. at android.view.ViewRoot.checkThread(ViewRoot.java:2934) ... at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:130) at android.os.HandlerThread.run(HandlerThread.java:60)
Журнал показывает, что onProgressUpdate
и onPostExecute
выполняются на HandlerThread
который по существу является рабочим потоком с пользовательским Looper
. Вот почему происходит авария.
Поэтому в вашем случае, вероятно, внутренний обработчик AsyncTask
связан с не основным петлером, связанным с рабочим потоком, например HandlerThread
а onUpdateProgress
обрабатывается вместо рабочего потока.
Я обнаружил, что эта ошибка появляется повсеместно на устройствах Android 2.3. Поэтому я проверил исходный код AsyncTask
в 2.3 и нашел следующее:
private static final InternalHandler sHandler = new InternalHandler(); private static class InternalHandler extends Handler { @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override public void handleMessage(Message msg) { ... } }
Вероятность того, что внутренний обработчик может быть привязан к не основному петлеукладчику.
Я также проверил последний исходный код AsyncTask
и увидел изменение:
private static class InternalHandler extends Handler { public InternalHandler() { super(Looper.getMainLooper()); } ... }
Конструктор InternalHandler
исключает вероятность того, что он может быть связан с не основным onUpdateProgress
поэтому onUpdateProgress
ведет себя нормально на почтовых устройствах Android 2.3.