0

我有一个应用程序,用户可能需要下载多达 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)条线似乎有点“hackish”。

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

4

2 回答 2

3

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

于 2013-05-15T22:43:40.873 回答
1

这是您需要记住的事情:

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

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

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

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

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

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

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

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

于 2013-05-15T23:30:23.107 回答