【问题标题】:Solution for downloading hundreds of files asynchronously异步下载数百个文件的解决方案
【发布时间】:2013-05-15 22:40:03
【问题描述】:

我有一个应用程序,用户可能需要在其中下载多达 760 个文件,总计约 350MB。 不可能压缩这些文件,它们必须作为松散文件下载!

我目前使用Android Asynchronous Http Client 下载单个文件,并使用AsyncTask 运行整个过程。

这是一个DownloadThread 对象的示例,它在后台处理下载数百个文件:

public class DownloadThread extends AsyncTask<String,String,String> {

ArrayList<String> list;
AsyncHttpClient client;
String[] allowedContentTypes = new String[] { "audio/mpeg" };
BufferedOutputStream bos;
FileOutputStream fos;

@Override
protected String doInBackground(String... params) {
    DownloadTask task;
    for (String file : list) {
        //the "list" variable has already been populated with hundreds of strings
        task = new DownloadTask(file);
        task.execute("");
        while (!task.isdone)
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }

    return null;
}


class DownloadTask extends AsyncTask<String, String, String> {

    String character, filename;
    boolean isdone = false;

    public DownloadTask(String file) {
        //file = something like "Whale/sadwhale.mp3"
        character = file.split("/")[0];
        filename = file.split("/")[1];
    }

    @Override
    protected void onPreExecute() {
    }

    @Override
    protected void onPostExecute(String result) {
        if (!result.equals("Error")) {
                        //Do something on success
        }
        isdone = true;
    }

    @Override
    protected String doInBackground(String... str) {
        client = new AsyncHttpClient();
        client.get("http://some-site.com/sounds/" + character + "/"
                + filename, new BinaryHttpResponseHandler(
                allowedContentTypes) {
            @Override
            public void onSuccess(byte[] fileData) {
                try {
                    // Make file/folder and create stream
                    File folder = new File(Environment
                            .getExternalStorageDirectory()
                            + CharSelect.directory + character);
                    folder.mkdirs();
                    File dest = new File(folder, filename);
                    fos = new FileOutputStream(dest);
                    bos = new BufferedOutputStream(fos);
                    // Transfer data to file
                    bos.write(fileData);
                    bos.flush();
                    bos.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        return "Success";
    }

}

}

DownloadThread 在后台运行,并调用数百个它自己的AsyncTasks。它一直等到任务完成下载,然后为每次下载继续 for 循环。

这行得通,有点。某些下载似乎无法正常完成或根本无法启动。在 760 次下载列表中,平均 100 次下载正确完成,我必须重新启动该过程以下载另外 100 次下载,直到该下载也失败。我感觉这是由于时间问题,Thread.sleep(10) 行似乎有点“骇人听闻”。

当然,从另一个AsyncTask 调用数百个AsyncTasks 并不是最有效的方法。如何更改此代码或实施第 3 方解决方案以适应此任务?

【问题讨论】:

  • 真的需要异步下载吗?我觉得将它们排成队列并一次下载一个就可以了。
  • 它没有必须,但通过异步执行此操作,我可以(最终)一次管理 2 或 3 个下载,从而提高整体速度。当然,我首先需要一个可靠的方法。

标签: java android asynchronous httprequest


【解决方案1】:

试用DownloadManager API。这应该是你需要的。

【讨论】:

  • 没想到这是O_O内置的 一定要看看!
【解决方案2】:

这是你需要记住的事情:

计算机资源有限;网络带宽、CPU、内存、磁盘等

一次下载 1 个文件与同时下载 760 个文件所需的时间在逻辑上永远不会比同时下载更长。

但是,通过生成大量后台任务/线程,您会招致大量线程抖动/开销,因为每个任务/线程都需要上下文切换。 CPU 带宽将在交换中消耗,而不是实际将数据移入和移出网络接口。此外,每个线程都将消耗它自己的内存,如果不是池的一部分,则可能需要创建。

基本上,您的应用无法可靠/根本无法运行的原因几乎可以肯定是因为它在完成下载或充分利用网络之前就已经耗尽了 CPU/DISK-IO/内存资源。

解决方案:找到一个库来执行此操作,或者使用 Executor 类套件并使用有限的线程池(然后一次只下载几个)。

这里有一些很好的证据表明不建议您尝试做的事情:

  • Google play 更新全部序列化
  • 亚马逊MP3文件下载器已完全序列化
  • Linux中默认scp客户端是序列化文件传输
  • Windows 更新串行下载

获取图片?喷出所有这些线程是导致问题的秘诀,以换取感知速度的提高。

【讨论】:

    猜你喜欢
    • 2018-03-03
    • 2023-04-09
    • 2011-02-05
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 1970-01-01
    • 2020-01-06
    • 2021-09-27
    相关资源
    最近更新 更多