为什么我在 AsyncTask 中收到此 ClassCastException?
首先,请不要对此进行解释。它只是大量可快速扫描的代码。实际的句子很少而且简洁:)。
我有一个奇怪的问题。 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您要传递什么
AsyncTask
来重试?AsyncTask
只能执行一次,因此您需要创建一个新实例,而不是尝试重新启动已执行的实例。摘自AsyncTask的javadoc:任务可以被执行仅一次(如果尝试第二次执行,将引发异常。)
编辑:..这就是我解释堆栈跟踪的方式。在 AsyncTask 中执行 done 时出现问题。错误的地方在于将
Object[]
强制转换为它不是的东西。可能是从doInBackground
到onPostExecute
时,但这只是一个疯狂的猜测。如果您正在尝试执行此操作,则可能是由任务重新启动引起的。What
AsyncTask
are you passing in to retry? anAsyncTask
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 fromdoInBackground
toonPostExecute
, 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.这
是看到
new EventsFetcher(dialog)
映射到final AsyncTask retry
这是原因吗?}
Here is see
new EventsFetcher(dialog)
is mapped tofinal AsyncTask retry
is this the cause?刚刚遇到了同样的问题。解决方案不是公认的答案,而是下面的 felix 评论:
确保您的 AsyncTask 引用是类型安全的。含义:使用
AsyncTask
而不仅仅是AsyncTask
。后者似乎默认为AsyncTask
,因此来自Object
的 ClassCastExceptionJust 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 justAsyncTask
. Latter seems to default toAsyncTask<Object, Object, Object>
and therefore the ClassCastException fromObject