Android 异步任务OnProgressUpdate CalledFromErrorThreadException:只有创建视图层次结构的原始线程才能接触其视图

Android 异步任务OnProgressUpdate CalledFromErrorThreadException:只有创建视图层次结构的原始线程才能接触其视图,android,multithreading,android-asynctask,Android,Multithreading,Android Asynctask,我正在使用AsyncTask下载一个数据库,其中有一个progressdialog,显示UI上的进度。我的一些用户收到错误信息: CalledFromErrorThreadException:只有创建视图层次结构的原始线程才能接触其视图 据我所知,只有当您试图在UI线程之外更新视图时,才会发生这种情况。以下是错误: com…updateops.DbCreate.onProgressUpdate(DbCreate.java:70) 在com…updateops.DbCreate.onProgres

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

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

据我所知,只有当您试图在UI线程之外更新视图时,才会发生这种情况。以下是错误:

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);
}
公共类DbCreate扩展异步任务{
私有静态上下文mCtx;
私有静态进程对话框mDialog;
公共静态AmazonSimpleDBClient mSDbClient;
公共静态AmazonS3客户端MS3客户端;
私有静态int-mAppVersion;
私有静态布尔mCreate;
公共DbCreate(上下文ctx、int-versionCode、布尔创建){
mCtx=ctx.getApplicationContext();
mAppVersion=版本代码;
mDialog=新进度对话框(ctx);
mDialog.setProgressStyle(ProgressDialog.STYLE_水平);
setMessage(“正在检查服务器访问。请稍候…”);
mDialog.setCancelable(假);
mDialog.setMax(1);
mDialog.show();
mCreate=create;
}
受保护的void onProgressUpdate(字符串…名称){
如果(名称[0]。等于(“项”)){
mDialog.incrementProgressBy(1);
}else if(名称[0].equals(“setMax”)){
mDialog.setProgress(0);

mDialog.setMax(Integer.parseInt(名称[1]);根据调用publishProgress(进度…)后在UI线程上调用onProgressUpdate(进度…)

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


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

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


这肯定会解决您的问题,但我不知道您第一手为什么会出错。我以前见过这种问题,但从未找到具体的原因。

我遇到了与您描述的相同的问题,我通过对AsyncTask所拥有的上下文使用
runOnUiThread()
调用来解决它(如您在示例中所示)

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

    @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
上执行,HandlerThread本质上是一个带有自定义
循环器的工作线程。因此,这就是崩溃发生的原因

因此,在您的情况下,
AsyncTask
的内部处理程序很可能绑定到与工作线程(如
HandlerThread
)相关联的非主循环器,而
onUpdateProgress
则在工作线程上处理

我发现这个bug在Android 2.3设备上随处可见。因此,我检查了2.3中
AsyncTask
的源代码,发现:

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设备上表现正常。

正如错误所说,您不能触摸(更改/更新)任何视图(控件:如按钮、编辑文本等)超出主线程。我不确定,但也许您应该尝试:mCtx.mDialog.setMax(Integer.parseInt(name[1]));如果这是必需的,那么这段代码将永远不会工作。这是一份崩溃报告,我正在试图找到影响一小部分用户的根本原因和解决方案。可能是,您不是从UI线程调用此异步。我是从UI线程调用此异步。它只在一个位置调用。处理程序解决方案有效。我仍然不确定e发生这种情况的原因(仅在部分手机/OS版本上发生)。我只能在运行2.3.3的N1上复制它,但开发人员控制台中也有报告。处理程序解决方案有效,但我必须将它交给Robin,因为它已在较早时发布。尽管我从未发现问题……这也解决了我的问题,只不过我只是运行了
rununuithread(new Runnable()…
没有活动引用。