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.
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.
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) {
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
精彩评论