4

我正在使用 AsyncTask 下载带有进度对话框的数据库,该对话框显示 UI 上的进度。我的一些用户收到错误:

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

据我了解,只有当您尝试从 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);
}

在我看来,我完全按照我应该做的事情来避免这个错误。有人知道为什么会这样吗?

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

4

4 回答 4

5

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

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

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

于 2013-09-04T00:47:22.730 回答
1

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

这肯定会解决您的问题,但我不知道您为什么一开始就会出错。我以前见过这种问题,但从来没有具体的原因。

于 2013-09-04T00:51:30.220 回答
1

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

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

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

值得注意的是, myAsyncTask最初是从 a中调用的AlertDialog,我认为这是导致问题开始的原因。

于 2014-10-17T14:33:25.613 回答
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)

日志表明onProgressUpdate并在其onPostExecute上执行HandlerThread本质上是一个具有自定义Looper. 所以这就是崩溃发生的原因。

因此,在您的情况下,内部处理程序很可能AsyncTask绑定到与工作线程相关联的非主循环器,而不是在工作线程HandlerThreadonUpdateProgress处理。

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

于 2015-07-23T05:10:12.647 回答