Android Executor上的AsyncTask和PriorityBlockingQueue实现问题
在的浪潮中,我尝试实现一个Android Executor上的AsyncTask和PriorityBlockingQueue实现问题,android,multithreading,android-asynctask,priority-queue,Android,Multithreading,Android Asynctask,Priority Queue,在的浪潮中,我尝试实现一个AsyncTask变体,其中包含可以优先排序的任务 在我的CustomAsyncTask课程中,我有: public abstract class CustomAsyncTask<Params, Progress, Result> { private static int CORE_POOL_SIZE = 1; private static int MAXIMUM_POOL_SIZE = 1; private static fin
AsyncTask
变体,其中包含可以优先排序的任务
在我的CustomAsyncTask
课程中,我有:
public abstract class CustomAsyncTask<Params, Progress, Result> {
private static int CORE_POOL_SIZE = 1;
private static int MAXIMUM_POOL_SIZE = 1;
private static final int KEEP_ALIVE = 1;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "CustomAsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue<DownloadTask> pPoolWorkQueue =
new PriorityBlockingQueue<DownloadTask>(10, new DownloadTasksComparator());
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Executor PRIORITY_THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, (PriorityBlockingQueue) pPoolWorkQueue, sThreadFactory);
//...
}
这是可行的:如果池大小为1,下载将逐个执行;如果池大小为2,等等
注意:优先级整数具有任意值:
public static final int PRIORITY_HIGH = 10;
public static final int PRIORITY_NORMAL = 1;
但如果我将这些任务称为:
DownloadTask dt = new DownloadTask(..., PRIORITY_HIGH, ...);
dt.executeOnExecutor(CustomAsyncTask.PRIORITY_THREAD_POOL_EXECUTOR);
我有一个java.lang.ClassCastException:my.pkg.name.CustomAsyncTask$3不能强制转换为my.pkg.name.DownloadTask
然后
at my.pkg.name.DownloadTasksComparator.compare(DownloadTasksComparator.java:1)
at java.util.concurrent.PriorityBlockingQueue.siftUpUsingComparator(PriorityBlockingQueue.java:334)
at java.util.concurrent.PriorityBlockingQueue.offer(PriorityBlockingQueue.java:447)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1295)
at my.pkg.name.CustomAsyncTask.executeOnExecutor(CustomAsyncTask.java:494)
at my.pkg.name.GetDownloadTaskListener$1.finishDownload(GetDownloadTaskListener.java:180)
at my.pkg.name.DownloadTask.onPostExecute(DownloadTask.java:330)
at my.pkg.name.DownloadTask.onPostExecute(DownloadTask.java:1)
at my.pkg.name.CustomAsyncTask.finish(CustomAsyncTask.java:536)
at my.pkg.name.CustomAsyncTask.access$0(CustomAsyncTask.java:532)
at my.pkg.name.CustomAsyncTask$InternalHandler.handleMessage(CustomAsyncTask.java:549)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
全部来自AndroidRuntime
我真的不知道
编辑:此时,我已经包装了一个小型Eclipse项目,该项目的实现方式与大型应用程序完全相同,并且存在相同的问题。它借用了CustomAsyncTaskComparator
和CustomAsyncTask
逐字记录。没有视觉反馈。应用程序的进度只是一些LogCat输出。但它给出了一个想法。当两个以上的任务排队时,应用程序FCs
CustomAsyncTask
,与AsyncTask
一样,使用静态
队列。目前,该队列上的所有内容都将通过您的下载任务比较程序运行。但是,downloadstaskscomparator
仅适用于downloadstask
。只要您只使用DownloadTask
,而不使用CustomAsyncTask
的其他子类,就可以了。但是,显然您还有一些其他匿名内部类扩展了CustomAsyncTask
,而这不是DownloadTask
使用getPriority()
方法作为abstract
方法,使CustomAsyncTask
成为abstract
。将DownloadTaskComparator
重命名为CustomAsyncTaskComparator
,并让它比较CustomAsyncTask
实例。然后,CustomAsyncTask
的其他子类需要实现它们自己的getPriority()
方法,以使它们能够与工作队列中的DownloadTask
实例一起排序。CustomAsyncTask
与AsyncTask
一样,使用静态队列。目前,该队列上的所有内容都将通过您的下载任务比较程序运行。但是,downloadstaskscomparator
仅适用于downloadstask
。只要您只使用DownloadTask
,而不使用CustomAsyncTask
的其他子类,就可以了。但是,显然您还有一些其他匿名内部类扩展了CustomAsyncTask
,而这不是DownloadTask
使用getPriority()
方法作为abstract
方法,使CustomAsyncTask
成为abstract
。将DownloadTaskComparator
重命名为CustomAsyncTaskComparator
,并让它比较CustomAsyncTask
实例。然后,CustomAsyncTask
的其他子类需要实现它们自己的getPriority()
方法,以使它们能够与工作队列中的DownloadTask
实例一起排序。CustomAsyncTask
与AsyncTask
一样,使用静态队列。目前,该队列上的所有内容都将通过您的下载任务比较程序运行。但是,downloadstaskscomparator
仅适用于downloadstask
。只要您只使用DownloadTask
,而不使用CustomAsyncTask
的其他子类,就可以了。但是,显然您还有一些其他匿名内部类扩展了CustomAsyncTask
,而这不是DownloadTask
使用getPriority()
方法作为abstract
方法,使CustomAsyncTask
成为abstract
。将DownloadTaskComparator
重命名为CustomAsyncTaskComparator
,并让它比较CustomAsyncTask
实例。然后,CustomAsyncTask
的其他子类需要实现它们自己的getPriority()
方法,以使它们能够与工作队列中的DownloadTask
实例一起排序。CustomAsyncTask
与AsyncTask
一样,使用静态队列。目前,该队列上的所有内容都将通过您的下载任务比较程序运行。但是,downloadstaskscomparator
仅适用于downloadstask
。只要您只使用DownloadTask
,而不使用CustomAsyncTask
的其他子类,就可以了。但是,显然您还有一些其他匿名内部类扩展了CustomAsyncTask
,而这不是DownloadTask
使用getPriority()
方法作为abstract
方法,使CustomAsyncTask
成为abstract
。将DownloadTaskComparator
重命名为CustomAsyncTaskComparator
,并让它比较CustomAsyncTask
实例。然后,CustomAsyncTask
的其他子类需要实现它们自己的getPriority()
方法,以使它们能够与工作队列中的DownloadTask
实例一起排序。正如您在查看AsyncTask
实现时可能注意到的那样,它在内部使用一个FutureTask
来处理后台任务,这就是交给Executor
并可能在其工作队列中排队的任务。由于您已经在派生自己的实现,因此可以将FutureTask
替换为一个自定义派生,该派生包含对AsyncTask
的引用,可从比较器访问
DownloadTask dt = new DownloadTask(..., PRIORITY_HIGH, ...);
dt.executeOnExecutor(CustomAsyncTask.PRIORITY_THREAD_POOL_EXECUTOR);
at my.pkg.name.DownloadTasksComparator.compare(DownloadTasksComparator.java:1)
at java.util.concurrent.PriorityBlockingQueue.siftUpUsingComparator(PriorityBlockingQueue.java:334)
at java.util.concurrent.PriorityBlockingQueue.offer(PriorityBlockingQueue.java:447)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1295)
at my.pkg.name.CustomAsyncTask.executeOnExecutor(CustomAsyncTask.java:494)
at my.pkg.name.GetDownloadTaskListener$1.finishDownload(GetDownloadTaskListener.java:180)
at my.pkg.name.DownloadTask.onPostExecute(DownloadTask.java:330)
at my.pkg.name.DownloadTask.onPostExecute(DownloadTask.java:1)
at my.pkg.name.CustomAsyncTask.finish(CustomAsyncTask.java:536)
at my.pkg.name.CustomAsyncTask.access$0(CustomAsyncTask.java:532)
at my.pkg.name.CustomAsyncTask$InternalHandler.handleMessage(CustomAsyncTask.java:549)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
/* Executor used by AsyncTask. Use it with executeOnExecutor()*/
class PriorityExecutor extends ThreadPoolExecutor{
//workQueue is a instance of PriorityBlockingQueue<Runnable>
public PriorityExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,threadFactory);
}
//wrap the runnable passed in.
@Override
public void execute(Runnable command) {
super.execute(new PriorityRunnableWrapper(command));
}
}
//a wrapper class
class PriorityRunnableWrapper implements Runnable ,Comparable<PriorityRunnableWrapper>{
long addedTime;//the "priority"
Runnable r;
public PriorityRunnableWrapper(Runnable r){
this.r = r;
addedTime = System.nanoTime();//in my case the timestamp is the priority
}
@Override
public void run() {
r.run();
}
@Override
public int compareTo(PriorityRunnableWrapper another) {
if(addedTime == another.addedTime)return 0;
return addedTime - another.addedTime > 0 ? -1 : 1;
}
}