如何用队列管理AsyncTask

logan676 发布于 2014/12/01 18:50
阅读 1K+
收藏 2

我最近在写一个Android文件下载的模块,具体的实现是这样的。

当用户选择多个文件或着文件夹后,获取到选择的文件路径,并放到一个数组中。使用循环遍历这个数组,为数组中的每一个文件创建一个AsyncTask实例(为每个文件开辟一个新线程),并执行它的execute方法。

为了测试这个模块,我下载了20张图片,每张图片1兆左右,结果图片可以稳定地下载(只不过UI更新进度有问题,有的文件已经下载完毕却还显示的是下载到了百分之多少)。

问题是,假如下载的不是20张图片,而是2000张图片的话,按照上面的做法,它会开启2000个线程。虽然Android SDK默认只执行前五个线程,其余线程处于等待。但是2000个AsyncTask实例已经调用了execute方法,系统已经分配了资源,所以我担心这样会拖慢系统性能,甚至内存溢出。

既然这样设计是有缺陷的,为了避免这个问题,那么我想使用队列来管理这2000个AsyncTask实例,先拿出前5个执行,待执行完毕后,队列中的等待的实例再出列并调用它的execute方法。我对AsyncTask不熟悉,不知道这样想对不对呢?还望前辈们多多指点。

method for add download task

    /**
     * Add a new download task
     */
    public int addDownloadTask(Account account,
                               String repoName,
                               String repoID,
                               String path) {
        // omit lines...
        DownloadTask task = new DownloadTask(account, repoName, repoID, path);
        // execute download task serially
        task.execute();
        return task.getTaskID();
    }

call addDownloadTask in a loop 

for (SeafDirent seafDirent : dirents) {
            if (!seafDirent.isDir()) {
                File localCachedFile = dataManager.
                        getLocalCachedFile(repoName,
                                           repoID,
                                           seafDirent.name),
                                           seafDirent.id);
                if (localCachedFile == null) {
                    txService.addDownloadTask(account, 
                                              repoName,
                                              repoID,
                                              Utils.pathJoin(filePath, 
                                                      seafDirent.name));
                }
            }
        }
加载中
0
logan676
logan676
 这个问题已经使用队列来实现了。
private List<DownloadTask> downloadingList = Lists.newArrayList();
    private List<DownloadTask> downloadWaitingList = Lists.newArrayList();
    // private static int mDownloadingCount = 0;
    private static final int DOWNLOAD_MAX_COUNT = 1;

    public void addTaskToDownloadQue(Account account,
                                     String repoName,
                                     String repoID,
                                     String path) {
        synchronized (downloadWaitingList) {
            boolean hasInQue = false;
            int index = -1;
            for (DownloadTask downloadTask : downloadWaitingList) {
                if (downloadTask.myRepoName.equals(repoName) &&
                        downloadTask.myPath.equals(path)) {
                    hasInQue = true;
                    index = downloadTask.getTaskID();
                    // Log.d(DEBUG_TAG, "in  Que  " + index + " " + repoName + path + "in waiting list");
                    break;
                }
            }

            for (DownloadTask downloadTask : downloadingList) {
                if (downloadTask.myRepoName.equals(repoName) &&
                        downloadTask.myPath.equals(path)) {
                    hasInQue = true;
                    index = downloadTask.getTaskID();
                    // Log.d(DEBUG_TAG, "in  Que  " + index + " " + repoName + path + " in downloading list" );
                    break;
                }
            }

            if (hasInQue) {
                // Log.d(DEBUG_TAG, "in  Que  " + index + " " + repoName + path );
            } else {
                DownloadTask task = new DownloadTask(account, repoName, repoID, path);

                // Log.d(DEBUG_TAG, "add Que  " + task.getTaskID() + " " + repoName + path);
                downloadWaitingList.add(task);
                downloadNext();
            }
        }
    }

    private void downloadNext() {
        // Log.d(DEBUG_TAG, "DownloadingCount:" + mDownloadingCount);
        if (!downloadWaitingList.isEmpty()
                && downloadingList.size() < DOWNLOAD_MAX_COUNT) {
            // mDownloadingCount++;
            // Log.d(DEBUG_TAG, "do next!");

            DownloadTask item = downloadWaitingList.get(0);
            downloadingList.add(item);
            downloadWaitingList.remove(0);
            item.execute();
        }
    }

    private void downloadNextInQue(int taskID) {
        synchronized (downloadWaitingList) {
            removeCurrentDownloadItem(taskID);
            downloadNext();
        }
    }

    private void removeCurrentDownloadItem(int taskID) {
        // Log.d(DEBUG_TAG, "removeCurrentDownloadItem:" + taskID);

        if (!downloadingList.isEmpty()) {
            DownloadTask toRemove = getDownloadTaskByID(taskID);
            for (int i = 0; i < downloadingList.size(); i++) {
                if (downloadingList.get(i).myRepoName.equals(toRemove.myRepoName) &&
                        downloadingList.get(i).myPath.equals(toRemove.myPath)) {
                    // Log.d(DEBUG_TAG, "Done Que " + taskID + " " + toRemove.myRepoName + toRemove.myPath);
                    downloadingList.remove(i);
                    break;
                }
            }
        }

    }

# 下载

## 添加下载任务

1. 把这些文件添加到下载等待队列


## 使用队列管理下载任务

1. 使用下载等待队列和下载队列管理下载任务

2. 设置一个允许同时下载的最大任务数

3. 当下载队列中任务数小于最大任务数时,从下载等待队列中获取新的下载任务

4. 当某个下载任务执行完成后,从下载队列移除它,并从下载等待队列获取一个新的下载任务,依次类推,直到下载等待队列为空

## 下载列表下载进度刷新

1. 使用定时器,每1s触发一个刷新事件

2. 每次刷新,获取一次数据源





1
朱宏青
朱宏青

http://my.oschina.net/kymjs/blog/350565

0
iuKa
iuKa
https://github.com/xckevin/Android-Download-Component
返回顶部
顶部