Android java.util.concurrent.RejectedExecutionException:从java.util.concurrent中拒绝的任务android.os.AsyncTask

时间:2014-08-19 15:41:32

标签: android android-fragments android-asynctask threadpool

我在listview上的线程池上创建asynchtask。我通过asynchtask的listarray处理这些任务。当片段被破坏时我必须删除那些任务,并且当我在销毁最后一个片段后创建新片段时必须再次分配这些任务。

我在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);
        }
    }

问题是我无法移除和取消最后的asynchtask线程,这导致 rejectedExecuationException 并且不允许它在线程池大小到达时创建新线程。 请告诉我如何克服这个问题?所以我的进度栏运行顺利,让我免于这个错误。

再次提醒我有一个包含listview的片段。

1 个答案:

答案 0 :(得分:4)

在您的情况下,很容易得到此异常。 ThreadPoolExecutor

  

当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();
}

如果您确实有特殊线程(例如播放器线程)计算进度,则无需启动新线程,只需从此线程进行进度更新。