我正在 Listview 上的线程池上创建 AsyncTask。我通过 AsyncTask 数组处理这些任务。当片段被销毁时,我必须删除这些任务,并且每当我在销毁最后一个片段后创建一个新片段时,我都必须再次分配这些任务。
我在Listview适配器中的代码是:
if(FragmentNowPlaying.task.isEmpty()){
FragmentNowPlaying.task.add( new ProgressAsynchTask(holder.info,tvShows, position));
FragmentNowPlaying.task.get(position).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else if(position >= FragmentNowPlaying.task.size()){
FragmentNowPlaying.task.add( new ProgressAsynchTask(holder.info,tvShows, position));
FragmentNowPlaying.task.get(position).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else if(position < FragmentNowPlaying.task.size()){
if(FragmentNowPlaying.task.get(position).getStatus().RUNNING == null){
FragmentNowPlaying.task.remove(position);
FragmentNowPlaying.task.add( new ProgressAsynchTask(holder.info,tvShows, position));
FragmentNowPlaying.task.get(position).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else if(FragmentNowPlaying.task.get(position).getStatus().RUNNING != null){
FragmentNowPlaying.task.get(position).cancel(true);
FragmentNowPlaying.task.remove(position);
FragmentNowPlaying.task.add( new ProgressAsynchTask(holder.info,tvShows, position));
FragmentNowPlaying.task.get(FragmentNowPlaying.task.size()-1).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
}
问题是我无法删除和取消最后一个 AsyncTask 线程,这导致 rejectedExecuationException 并且它不允许我在达到线程池大小时创建新线程。 请告诉我如何解决这个问题?
就您而言,很容易出现此异常。 线程池执行器
当 Executor 关闭时,以及当 Executor 使用最大线程和工作队列容量的有限界限并且饱和时,在方法execute(Runnable)中提交的新任务将被拒绝。
任务拒绝导致生成RejectedExecutionException。在您的情况下,达到了最大线程数。线程和任务限制取决于 Android 平台版本,例如 Android 4.0.1 MAXIMUM_POOL_SIZE = 128。
这就是为什么即使您有像示例中那样的逻辑,也很容易达到列表中 128 个项目的线程限制,特别是如果它是长时间运行的任务。
我认为更新列表中的进度栏不需要每个列表项有单独的线程。从我的角度来看,一个 Thread 或 AsyncTask 足以完成这项工作。没有足够的代码来进行适当的重构,但最简单的概念如下:
Handler uiHandler = new Handler(Looper.getMainLooper());
//Somewhere in your activity
Thread updateThread = new Thread(){
@Override
public void run() {
while(!isInterrupted()){
final Map<Integer, Integer> progressStates = getCurrentProgress();
uiHandler.post(new Runnable() {
@Override
public void run() {
for (int i = 0; i < adapter.getCount(); i++) {
int progress = progressStates.get(i);
adapter.getItem(i).setProgress();//It's not default method you need to implement it in your item
}
adapter.notifyDataSetChanged();
}
});
try {
sleep(1000); //Schedule next update in 1 second
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private Map getCurrentProgress(){
//do long running operation here
...
return progresStates;
}
}.start();
//Don't forget stop this thread if user gone from screen. For example in your activity
public void onDestroy(){
updateThread.interrupt();
}
如果您实际上有特殊的线程(例如玩家线程)来计算进度,则无需启动新的线程,只需从此线程进行进度更新即可。