我想创建一个类,该类将在ThreadExceutor
上同时执行多个任务(由工厂生成(。但是,我在此类使用的泛型方面遇到了问题。
这涉及三个类/接口:
-
ConcurrentAsyncTask
,一个抽象类,用于管理任务多次执行的结果的同步和合并。它的参数和返回值是通用的。同时执行的所有任务都会扩展它。 -
TaskFactory
是一个通用接口,用于创建要并发执行的任务。这仅用于创建任务的多个实例,以便它们可以并行运行。 -
TestTaskAsync
,一个扩展ConcurrentAsyncTask
的示例并行任务。
我ConcurrentAsyncTask
是
public abstract class ConcurrentAsyncTask<Params, Result> extends AsyncTask<Params, Void, List<Result>> {
...
public static <P, R> void executeConcurrent(TaskFactory<P, R> factory, TaskCallback<R> callback, P[] params){
AtomicInteger remainingCounter = new AtomicInteger(params.length);
List<R> resultList = new Vector<R>();
for(P param : params){
ConcurrentAsyncTask<P,R> task = factory.createTask(remainingCounter, resultList, callback);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, param);
}
}
}
TaskFactory
在哪里
public interface TaskFactory<Params, Result> {
public ConcurrentAsyncTask<Params, Result> createTask(AtomicInteger remainingCounter, List<Result> resultList, TaskCallback<Result> callback);
}
和扩展类TestTaskAsync
public class TestTaskAsync extends ConcurrentAsyncTask<IMAPFolder, MessageIndex>{
public MessageIndexerAsync(AtomicInteger remainingCounter, List<MessageIndex> messageIndexes, TaskCallback<MessageIndex> callback) {
super(remainingCounter, messageIndexes, callback);
}
@Override
protected List<MessageIndex> doInBackground(IMAPFolder... folders) {
Log.d(TAG, "[doInBackground] Processing "+folders[0].getClass().getCanonicalName());
return new Vector<MessageIndex>();
}
}
我正在尝试执行这样的任务
ConcurrentAsyncTask.<IMAPFolder, MessageIndex>executeConcurrent(
new TaskFactory<IMAPFolder, MessageIndex>() {
@Override
public ConcurrentAsyncTask<IMAPFolder, MessageIndex> createTask(AtomicInteger remainingCounter, List<MessageIndex> resultList, TaskCallback<MessageIndex> callback) {
return new TestTaskAsync(remainingCounter, resultList, callback);
}
},
new TaskCallback<MessageIndex>(){
@Override
public void exec(List<MessageIndex> messageIndexes) {
}
},
imapFolders.toArray(new IMAPFolder[imapFolders.size()])
);
在此之后,我得到了一个未捕获的异常。添加UncaughtExceptionHandler
后,我发现问题出在AsyncTask
收到的类型中Params
12-10 17:58:33.272 10774-10818/(...) E/ConcurrentAsyncTask﹕
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:299)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
at java.util.concurrent.FutureTask.run(FutureTask.java:239)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:856)
Caused by: java.lang.ClassCastException: java.lang.Object[] cannot be cast to com.sun.mail.imap.IMAPFolder[]
at (...).TestTaskAsync.doInBackground(TestTaskAsync.java:19)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:856)
到目前为止,我找到了两种解决方案
- 将
TestTaskAsync
的原型更改为public class TestTaskAsync extends ConcurrentAsyncTask<Object, MessageIndex>
。使用这种方法,我验证了传递给我doInBackground
的Object
确实是IMAPFolder
的实例。这不是真正首选的方法。 - 将
TestTaskAsync
的原型更改为public class TestTaskAsync<T> extends ConcurrentAsyncTask<T, MessageIndex>
并按return new TestTaskAsync<IMAPFolder>(remainingCounter, resultList, callback);
创建实例 - 同样没有用。进一步使用第二种方法,我尝试了TestTaskAsync<T extends IMAPFolder>
,但是这导致了与以前相同的问题。
我正在使用gradle
编译我的代码,用于API15
。我错过了什么?
PS Android Studio告诉我,task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, param);
的行Unchecked generics array creation for vararg parameter
- 我猜这与它有关,但我不太明白它在这种情况下意味着什么。
编辑 检查factory.createTask(remainingCounter, resultList, callback)
的ActualTypeArguments
会给出正确的com.sun.mail.imap.IMAPFolder
值和com.philips.motiva.mail.MessageIndex
在创建数组参数的那一刻:Object[],你的应用程序对你将传递的类型一无所知,因为你的泛型类型P[]与你将编写Object[]相同。因此,在调用 executeOnExecutor 的那一刻,您的方法会传递 Object[] 数组,而不仅仅是引用 Object[]。如您所知,您不能将 Object[] 转换为 ChildOfObject[]。您还应该用 IMAPFolder 类型的参数覆盖您的方法 executeOnExecutor...然后它应该起作用。
但是如果你编写 task.execute((,你也会有同样的异常,因为你的执行方法也有 Object[] 类型的参数,而不是你的自定义泛型。使用子类型的参数重写方法不是好的做法。对你来说,接下来写会更好:
@Override
protected List<MessageIndex> doInBackground(Object... folders) {
if (folder[0] instanceof IMAPFolder) {
Log.d(TAG, "[doInBackground] Processing "+((IMAPFolder)folders[0]).getClass().getCanonicalName());
return new Vector<MessageIndex>();
} else {
return null;
}
}