在AsyncTask doInBackground中使用ThreadPoolExecutor是否安全

时间:2014-05-29 10:28:29

标签: android android-asynctask threadpoolexecutor

我必须下载带有文件列表的Json,然后并行下载列表中的文件。我想定期更新ProgressDialog,所以我以这种方式实施

  • 我创建并显示对话框
  • 我开始AsyncTask

    • onProgressUpdate收到2个整数,当前进度和最大进度,并更新进度条

    • doInBackground

      • 下载json文件并获取要下载的文件列表
      • 使用ThreadPoolExecutor
      • 创建LinkedBlockingQueue<Runnable>(tpe)
      • 为每个文件提交一个runnable,使用Apache commons-io FileUtils.copyURLToFile
      • 将文件下载到磁盘
      • exec shutdown
    • 在一段时间内。 tpe.awaitTermination(1,TimeUnit.SECONDS)定期调用 publishProgress((int)tpe.getCompletedTaskCount(),tot),以更新进度条
    • onPostExecute隐藏和解除progres栏,并管理文件下载

在AsynTask中使用ThreadPoolExecutor有什么问题吗? 我正在和一位同事讨论,他们声称线程管理中可能存在问题,可能会出现僵局,这可能会给我们未来版本带来问题

这就是代码

public static void syncFiles(...)
{
    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    sWakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    sWakelock.acquire();

    sProgress = new ProgressDialog(context);
    sProgress.setCancelable(false);
    sProgress.setTitle("MyTitle");
    sProgress.setMessage("Sincronizzazione in corso");
    sProgress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    sProgress.setIndeterminate(false);
    sProgress.show();

    sCurrentTask = new AsyncTask<Void, Integer, Manifest>()
    {

        @Override
        protected void onCancelled()
        {
            if ((sProgress != null) && sProgress.isShowing())
                sProgress.dismiss();

            if ((sWakelock != null) && sWakelock.isHeld())
                sWakelock.release();
        };

        @Override
        protected Manifest doInBackground(Void... params)
        {
            ArrayList files = getFiles(....)// download the jsonfile, and return the list of files

            final String baseurl = ... //  get the remote base url
            final String baselocal = ... //get the local base path ;

            int tot = m.size();

            publishProgress(0, tot);

            final int MAX_THREADS = Runtime.getRuntime().availableProcessors(); * 4;

            ThreadPoolExecutor tpe = new ThreadPoolExecutor(
                            MAX_THREADS,
                            MAX_THREADS,
                            1,
                            TimeUnit.MINUTES,
                            new LinkedBlockingQueue<Runnable>()
                            );

            for (final String s: files)
            {

                tpe.submit(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        try
                        {
                            URL remoteUrl = new URL(baseurl + s);
                            File localUrl = new File(baselocal, s);
                            FileUtils.copyURLToFile(remoteUrl, localUrl, 60000, 60000);
                            Log.w(TAG, "Downloaded " + localUrl.getAbsolutePath() + " in " + remoteUrl);
                        } catch (Exception e)
                        {
                            e.printStackTrace();
                            Log.e(TAG, "download error " + e);
                            // error management logic
                        }
                    }

                });
            }

            tpe.shutdown();
            int num = 0;
            publishProgress(num, tot);
            try
            {
                while (!tpe.awaitTermination(1, TimeUnit.SECONDS))
                {
                    int n = (int) tpe.getCompletedTaskCount();
                    Log.w(TAG, "COUTN:  " + n + "/" + tot);
                    if (n != num)
                    {
                        num = n;
                        publishProgress(num, tot);
                    }
                }
            } catch (InterruptedException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            return m;
        }

        protected void onProgressUpdate(Integer... prog)
        {
       if (sProgress.getMax() != prog[1])                {
                sProgress.setMax(prog[1]);
            }
            sProgress.setProgress(prog[0]);
        }

        @Override
        protected void onPostExecute(Manifest result)
        {

            sWakelock.release();
            sProgress.hide();
            sProgress.dismiss();

            // manage results
        }
    }.execute();
}

1 个答案:

答案 0 :(得分:0)

如果您要检查AsyncTask的实现,那么您可以发现AsyncTask本身具有ThreadPool,因此它将在单独的线程上启动任务。实际上,当我们可以通过.execute()来启动后台任务时,此方法通常与THREAD_POOL_EXECUTOR一起使用,以允许多个任务在由AsyncTask管理的线程池上并行运行。那么为什么你需要实现另一个。

更新 阅读this中的executeOnExecutor可能会对你有所帮助......它清楚地表明,如果你允许多个任务从线程池并行运行通常不是你想要的,因为它们的操作顺序是没有定义....但在这里你想下载文件,所以我认为订单不重要,所以在我看来你可以使用它,它不会产生任何问题。