AsyncTask等待其他AsyncTasks

时间:2014-03-08 11:46:14

标签: java android concurrency android-asynctask

我已经构建了多个asynctasks来处理多个不同的任务。主要目标是“重置数据”,其中包括:

  1. 删除数据库中的所有现有数据,表x
  2. 删除与数据相关的所有现有本地文件
  3. 提交网络请求以下载将提供“刷新”数据的JSON
  4. 解析JSON
  5. 将JSON存储在数据库中
  6. 根据JSON数据下载新的本地文件(即包含图像网址)
  7. 存储下载的文件
  8. 今天,我已经通过一个主要的AsyncTask'实现'了这个,它创建了多个'sub'-AsyncTasks来完成工作。以下任务代码:

    private class GetMetaDataTask extends AsyncTask<String, Integer, String> {
        private Context context;
        private ProgressDialog dialog;
        private List<MatchDetail> results;
        private long accountId;
    
        public GetMetaDataTask(Context c) {     
            this.context = c;
            this.dialog = new ProgressDialog(context);
        }
    
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            if (dialog != null) {
                dialog.setMessage("Downloading JSON...");
                dialog.show();
            }
        }
    
        @Override
        protected String doInBackground(String... inputs) {     
                /** Items **/
                List <Item> items = stats.getItemsMeta();
                List <MetaImageDownloader> metaDownloaders = new ArrayList<MetaImageDownloader>();
                if (items.size() > 0) {
                    new ResourceHelper(null, context).deleteLocalImages(ResourceHelper.PATH_ITEMS);
                    db.deleteItems();
                    for (Item i: items) {           
                        //Store in database
                        db.storeItem(i);
                        //Download images
                        new MetaImageDownloader(context, i.getItemImg(),MetaImageDownloader.JOB_DOWNLOAD_ITEM)).execute();
                    }
    
                }
            return null;
         }
    
         protected void onProgressUpdate(Integer... progress) {
         }
         @Override
         protected void onPostExecute(String result) {
    
             db.close();
                if (dialog != null) 
                    dialog.dismiss();
         }
    }
    

    以下是MetaImageDownloader的doInBackground代码:

    protected Void doInBackground(String... imgTypes) {
        ResourceHelper rh = new ResourceHelper(null, context);
        if (jobType == JOB_DOWNLOAD_ITEM) { 
            bmp = rh.getBitmapFromURL(getItemImageUrl(downloadCode));
            rh.saveImageLocally(bmp, ResourceHelper.PATH_ITEMS, downloadCode);
            if (bmp != null)
                bmp.recycle();
    
        } 
        ...
    

    要打破它,

    1)删除所有现有数据:

    db.deleteItems();

    2)删除与数据相关的所有现有本地文件:

    new ResourceHelper(null, context).deleteLocalImages(ResourceHelper.PATH_ITEMS);

    3/4)提交网页请求以下载将提供“刷新”数据的JSON&amp;解析:

    List <Item> items = stats.getItemsMeta();

    5)将JSON存储在数据库中 db.storeItem(i);

    6)根据JSON数据下载新的本地文件:

    new MetaImageDownloader(context, i.getItemImg(),MetaImageDownloader.JOB_DOWNLOAD_ITEM)).execute();

    (在MetaImageDownloader内) - bmp = rh.getBitmapFromURL(getItemImageUrl(downloadCode));

    7)存储下载的文件:

    (在MetaImageDownloader内) - rh.saveImageLocally(bmp, ResourceHelper.PATH_ITEMS, downloadCode);

    -

    呼!现在,#6是每个Item运行的新AsyncTask,可以同时同时下载所有图像。我遇到的挑战是能够确定所有 MetaImageDownloader AsyncTasks何时完成。每个下载的图像都可以获得PostExecute,但是当所有161个图像都已完成时,我不能。

    问题1 - 我是否通过在AsyncTask中创建AsyncTasks来破坏标准?我知道最大的问题是无法从这些'sub-AsyncTasks'

    更新UI

    问题2 - 当所有161个MetaImageDownloader AsyncTasks完成后,如何通知UI?

    更新:我创建了一个新功能来执行#6/7:

    public void batchDownloadSaveImages(List<Item> items, List<Hero> heroes, String heroImgTypes[]) throws ExecutionException, InterruptedException {
    List<Runnable> requests = new ArrayList<Runnable>();
    
        final ExecutorService pool = Executors
                .newFixedThreadPool(Const.MAX_THREAD_POOL);
        int reqCounter = 1;
    
        for (final Item item : items) {
            requests.add(new Runnable() {
    
                @Override
                public void run() {     
                    Bitmap bmp = getBitmapFromURL(getItemImageUrl(item.getItemImg()));
                    saveImageLocally(bmp, ResourceHelper.PATH_HEROES, item.getItemImg());
                }
            });
            reqCounter++;
        }
    
        List<Future> runnables = new ArrayList<Future>();
    
        for (Runnable request : requests) {
            runnables.add(pool.submit(request));
        }
    
        for (Future future : runnables) {
            synchronized (this) {
                System.out.println("- Received request. " + --reqCounter
                        + " requests to go!");
            }
        }
    
        // Wait till everything has calmed down!
        pool.shutdown();
    }
    

1 个答案:

答案 0 :(得分:0)

您尝试实现的标准模式如下:

function on_all_tasks_done() {
  // do something
}

tasks = generate_async_taks()
var nb_tasks = tasks.size()
var callback = function() {
  nb_tasks--
  if (nb_tasks == 0) on_all_tasks_done();
};

for (var i = 0; i < nb_tasks; i++) {
  var task = tasks[i]
  task.execute_then_invoke(callback)
}

扩展大评论部分: 这个问题的开头是:如果我有一组任务并以异步方式运行它们,我该如何对'all_tasks_done'事件作出反应。我回答了这个问题。现在你基本上都在问东西,比如:

'我应该如何构建我的代码?'或者'编写可维护异步代码的最佳策略是什么?'

这些问题不容易回答,更多的是你缺乏必要的术语。我担心我能做的只有这么多:)