为什么我在 AsyncTask 中收到此 ClassCastException?

发布于 2024-11-16 14:49:45 字数 3840 浏览 2 评论 0原文

首先,请不要对此进行解释。它只是大量可快速扫描的代码。实际的句子很少而且简洁:)。

我有一个奇怪的问题。 ClassCastException 强制关闭我的 Activity,但该异常并不表明问题实际出在哪里。例外情况如下:

E/AndroidRuntime(  402): FATAL EXCEPTION: AsyncTask #4
E/AndroidRuntime(  402): java.lang.RuntimeException: An error occured while executing doInBackground()
E/AndroidRuntime(  402):    at android.os.AsyncTask$3.done(AsyncTask.java:200)
E/AndroidRuntime(  402):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
E/AndroidRuntime(  402):    at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
E/AndroidRuntime(  402):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
E/AndroidRuntime(  402):    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
E/AndroidRuntime(  402):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
E/AndroidRuntime(  402):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
E/AndroidRuntime(  402):    at java.lang.Thread.run(Thread.java:1019)
E/AndroidRuntime(  402): Caused by: java.lang.ClassCastException: [Ljava.lang.Object;
E/AndroidRuntime(  402):    at mypackage.DayActivity$EventsFetcher.doInBackground(DayActivity.java:1)
E/AndroidRuntime(  402):    at android.os.AsyncTask$2.call(AsyncTask.java:185)
E/AndroidRuntime(  402):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
E/AndroidRuntime(  402):    ... 4 more
W/ActivityManager(   61):   Force finishing activity mypackage/mypackage.DayActivity

如您所见,它表明错误发生在 DayActivity.java 的第 1 行,这是默认的包声明(即 package mypackage)。

这是我的 doInBackground 方法。在这里,奇怪的情况加剧了,因为整个方法基本上是一个 try/catch 块:

@Override
protected List<Event> doInBackground(Void... params) {
    try {
        final List<Event> events;
        if (connectivityReceiver.hasConnection()) {
            events = WebApi.getEvents(Util.getSelectedUser(DayActivity.this).getId(), start, end);
        }
        else if (Util.isPeriodCached(DayActivity.this, start, end)) {
            final List<Event> allEvents = (List<Event>) new Cache(DayActivity.this).get(Cache.EVENTS);
            events = Util.filterEvents(allEvents, start, end, Util.getSelectedUser(DayActivity.this).getId());
        }
        else {
            events = null;
        }
        return events;
    }
    catch (Exception e) {
        Log.e(Const.TAG, "Could not fetch events for day view", e);
    }
    return null;
}

理论上,任何抛出的异常都应该被捕获并记录。我不明白这怎么可能发生。诀窍是,在 onPostExecute 中,我运行以下代码:

if (!connectivityReceiver.hasConnection()) {
    Util.retryDialog(DayActivity.this, R.string.no_cache, R.string.no_cache_msg,
        new EventsFetcher(dialog), false).show();
}

这是 retryDialog()

public static Dialog retryDialog(final Activity context, int titleRes, int messageRes,
        final AsyncTask retry, final boolean finishOnCancel) {
    return new AlertDialog.Builder(context)
        .setTitle(titleRes)
        .setMessage(messageRes)
        .setPositiveButton(R.string.retry, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (retry != null) {
                    retry.execute();
                }
            }
        })
        .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (finishOnCancel) {
                    context.finish();
                }
            }
        })
        .create();
}

问题是任务运行一次,对话框就会显示,但是当我单击时重试抛出异常,导致我的应用程序崩溃。

First off, please do not tl;dr this. It just a lot of quickly-scannable code. Actual sentences are few and concise :).

I have a weird problem. A ClassCastException is force-closing my Activity, but the exception does not indicate where the problem actually is. Here's the exception:

E/AndroidRuntime(  402): FATAL EXCEPTION: AsyncTask #4
E/AndroidRuntime(  402): java.lang.RuntimeException: An error occured while executing doInBackground()
E/AndroidRuntime(  402):    at android.os.AsyncTask$3.done(AsyncTask.java:200)
E/AndroidRuntime(  402):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
E/AndroidRuntime(  402):    at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
E/AndroidRuntime(  402):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
E/AndroidRuntime(  402):    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
E/AndroidRuntime(  402):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
E/AndroidRuntime(  402):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
E/AndroidRuntime(  402):    at java.lang.Thread.run(Thread.java:1019)
E/AndroidRuntime(  402): Caused by: java.lang.ClassCastException: [Ljava.lang.Object;
E/AndroidRuntime(  402):    at mypackage.DayActivity$EventsFetcher.doInBackground(DayActivity.java:1)
E/AndroidRuntime(  402):    at android.os.AsyncTask$2.call(AsyncTask.java:185)
E/AndroidRuntime(  402):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
E/AndroidRuntime(  402):    ... 4 more
W/ActivityManager(   61):   Force finishing activity mypackage/mypackage.DayActivity

As you can see, it says that the error occurs on line 1 of DayActivity.java, which is the default package declaration (i.e. package mypackage).

Here's my doInBackground method. Here, the weirdness intensifies, as the whole method is basically a try/catch block:

@Override
protected List<Event> doInBackground(Void... params) {
    try {
        final List<Event> events;
        if (connectivityReceiver.hasConnection()) {
            events = WebApi.getEvents(Util.getSelectedUser(DayActivity.this).getId(), start, end);
        }
        else if (Util.isPeriodCached(DayActivity.this, start, end)) {
            final List<Event> allEvents = (List<Event>) new Cache(DayActivity.this).get(Cache.EVENTS);
            events = Util.filterEvents(allEvents, start, end, Util.getSelectedUser(DayActivity.this).getId());
        }
        else {
            events = null;
        }
        return events;
    }
    catch (Exception e) {
        Log.e(Const.TAG, "Could not fetch events for day view", e);
    }
    return null;
}

In theory, any exception thrown should be caught and logged. I don't see how that could not happen. The trick is that in onPostExecute, I run this code:

if (!connectivityReceiver.hasConnection()) {
    Util.retryDialog(DayActivity.this, R.string.no_cache, R.string.no_cache_msg,
        new EventsFetcher(dialog), false).show();
}

Here's retryDialog():

public static Dialog retryDialog(final Activity context, int titleRes, int messageRes,
        final AsyncTask retry, final boolean finishOnCancel) {
    return new AlertDialog.Builder(context)
        .setTitle(titleRes)
        .setMessage(messageRes)
        .setPositiveButton(R.string.retry, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (retry != null) {
                    retry.execute();
                }
            }
        })
        .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (finishOnCancel) {
                    context.finish();
                }
            }
        })
        .create();
}

The problem is that the task works once, the dialog gets displayed, but then when I click retry that exception is thrown, crashing my app.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

南渊 2024-11-23 14:49:45

您要传递什么AsyncTask来重试? AsyncTask 只能执行一次,因此您需要创建一个新实例,而不是尝试重新启动已执行的实例。摘自AsyncTask的javadoc

任务可以被执行仅一次(如果尝试第二次执行,将引发异常。)

编辑:..这就是我解释堆栈跟踪的方式。在 AsyncTask 中执行 done 时出现问题。错误的地方在于将 Object[] 强制转换为它不是的东西。可能是从 doInBackgroundonPostExecute 时,但这只是一个疯狂的猜测。如果您正在尝试执行此操作,则可能是由任务重新启动引起的。

What AsyncTask are you passing in to retry? an AsyncTask can only execute once, so you need to create a new instance, and not try to restart the already executed instance. Taken from the javadoc for AsyncTask:

The task can be executed only once (an exception will be thrown if a second execution is attempted.)

Edit: .. this is how I interpret the stacktrace. Something is going wrong when executing done in AsyncTask. The thing that is wrong is a cast of Object[] to something that it isn't. Possibly when going from doInBackground to onPostExecute, but that's just a wild guess. Might be caused by a restart of the task, if that is what you are trying to do.

柠栀 2024-11-23 14:49:45
if (!connectivityReceiver.hasConnection()) {
Util.retryDialog(DayActivity.this, R.string.no_cache, R.string.no_cache_msg,
    new EventsFetcher(dialog), false).show();

是看到 new EventsFetcher(dialog) 映射到 final AsyncTask retry 这是原因吗?

public static Dialog retryDialog(final Activity context, int titleRes, int messageRes,
    final AsyncTask retry, final boolean finishOnCancel) {
if (!connectivityReceiver.hasConnection()) {
Util.retryDialog(DayActivity.this, R.string.no_cache, R.string.no_cache_msg,
    new EventsFetcher(dialog), false).show();

}

Here is see new EventsFetcher(dialog) is mapped to final AsyncTask retry is this the cause?

public static Dialog retryDialog(final Activity context, int titleRes, int messageRes,
    final AsyncTask retry, final boolean finishOnCancel) {
恰似旧人归 2024-11-23 14:49:45

刚刚遇到了同样的问题。解决方案不是公认的答案,而是下面的 felix 评论:
确保您的 AsyncTask 引用是类型安全的。含义:使用 AsyncTask 而不仅仅是 AsyncTask。后者似乎默认为 AsyncTask ,因此来自 Object 的 ClassCastException

Just had the same problem. The Solution is not the accepted answer but rather felix comment below it:
Make sure your AsyncTask reference is typesafe. Meaning: use AsyncTask<Your, Parameter, Types> instead of just AsyncTask. Latter seems to default to AsyncTask<Object, Object, Object> and therefore the ClassCastException from Object

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文