继承和通用异步任务的问题



我想创建一个类,该类将在ThreadExceutor上同时执行多个任务(由工厂生成(。但是,我在此类使用的泛型方面遇到了问题。

这涉及三个类/接口:

  1. ConcurrentAsyncTask ,一个抽象类,用于管理任务多次执行的结果的同步和合并。它的参数和返回值是通用的。同时执行的所有任务都会扩展它。
  2. TaskFactory 是一个通用接口,用于创建要并发执行的任务。这仅用于创建任务的多个实例,以便它们可以并行运行。
  3. 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)

到目前为止,我找到了两种解决方案

  1. TestTaskAsync的原型更改为public class TestTaskAsync extends ConcurrentAsyncTask<Object, MessageIndex>。使用这种方法,我验证了传递给我doInBackgroundObject确实是IMAPFolder的实例。这不是真正首选的方法。
  2. 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;
  }
}

最新更新