Async Task OnProgressUpdate CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触及其视图

时间:2013-09-04 00:15:43

标签: android multithreading android-asynctask

我正在使用AsyncTask下载一个数据库,其中包含一个显示UI进度的progressdialog。我的一些用户收到错误:

CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触及其视图。

据我所知,只有在尝试从UI线程更新Views时才会发生这种情况。这是错误:

... COM updateops.DbCreate.onProgressUpdate(DbCreate.java:70) 在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);
}

在我看来,我正在遵循我应该做的事情,以避免此错误。有人知道为什么会这样吗?

编辑:我还应该提到这段代码大部分时间都有效。我在开发者控制台上收到崩溃报告。

4 个答案:

答案 0 :(得分:5)

根据onProgressUpdate(Progress ...)在调用publishProgress(Progress ...)后在UI线程上调用。

您应该分析整个日志报告,以检查您的异步任务是否有可能在其他线程上创建。

如果你真的找不到根本原因,你可以使用在UI线程上创建的处理程序来解决。

答案 1 :(得分:1)

您的代码看起来很好,在大多数情况下它应该可以工作。我建议你使用处理程序。您可以在UI线程中编写处理程序,并从onProgressUpdate()调用它。这将完全确保UI工作在UI线程中完成。

这肯定会解决您的问题,但我不知道为什么您第一时间会遇到错误。我以前见过这种问题,从来没有得到具体的理由。

答案 2 :(得分:1)

我遇到了与您描述的问题相同的问题,我通过对AsyncTask所拥有的上下文进行runOnUiThread()调用来修复它(正如您在示例中所做的那样)。

以下解决方案应该解决您的问题;

    @Override
    protected void onProgressUpdate(final String... messages){
        myActivityReference.runOnUiThread(new Runnable() {
            @Override
            public void run() {          
                // Your UI changes here. 
           }
       });                 
    }

值得注意的是,AsyncTask最初是在AlertDialog内调用的,我认为这是导致问题开始的原因。

答案 3 :(得分:0)

我在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)

日志表明onProgressUpdateonPostExecuteHandlerThread上执行,Looper本质上是具有自定义AsyncTask的工作线程。这就是发生崩溃的原因。

因此,在您的情况下,HandlerThread的内部处理程序可能绑定到与onUpdateProgress之类的工作线程关联的非主looper,而AsyncTask则在工作线程上处理。

我发现这个bug在Android 2.3设备上普遍存在。因此,我在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构造函数消除了绑定到非主要循环器的可能性,因此-|在Android 2.3后设备上表现正常。