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

问题描述 投票:0回答:1

我正在 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 并且它不允许我在达到线程池大小时创建新线程。 请告诉我如何解决这个问题?

android android-fragments android-asynctask threadpool
1个回答
4
投票

就您而言,很容易出现此异常。 线程池执行器

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

如果您实际上有特殊的线程(例如玩家线程)来计算进度,则无需启动新的线程,只需从此线程进行进度更新即可。

© www.soinside.com 2019 - 2024. All rights reserved.