关键词

Android实现网络多线程文件下载

实现网络多线程文件下载在Android开发中非常常见,下面我会详细讲解这个过程的完整攻略。

1. 实现方式

Android实现网络多线程文件下载的方式是通过Java中的多线程实现的,其中主要使用到了Java IO和Java多线程的知识。可分为以下几个步骤:

  1. 创建HttpURLConnection对象,连接要下载的文件URL地址;
  2. 获取要下载的文件的总大小;
  3. 判断本地文件夹中的已下载文件的大小;
  4. 如果文件未下载完,计算下载文件的起始点和结束点;
  5. 创建多个线程,并启动下载;
  6. 下载完成后将文件保存到本地文件夹中。

2. 实现步骤

2.1 创建HttpURLConnection对象,连接要下载的文件URL地址

URL url = new URL(fileUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setRequestProperty("Connection", "Keep-Alive");

2.2 获取要下载的文件的总大小

int totalSize = conn.getContentLength();

2.3 判断本地文件夹中的已下载文件的大小

File downloadedFile = new File(path, fileName);
int downloadedSize = 0;
if (downloadedFile.exists()) {
    downloadedSize = (int) downloadedFile.length();
}

2.4 如果文件未下载完,计算下载文件的起始点和结束点

if (downloadedSize < totalSize) {
    int blockSize = (totalSize + THREAD_COUNT - 1) / THREAD_COUNT;
    for (int threadId = 0; threadId < THREAD_COUNT; threadId++) {
        int startIndex = threadId * blockSize;
        int endIndex = startIndex + blockSize - 1;
        if (threadId == THREAD_COUNT - 1) {
            endIndex = totalSize - 1;
        }
        downloaders[threadId] = new Downloader(threadId, startIndex, endIndex);
        downloaders[threadId].start();
    }
}

2.5 创建多个线程,并启动下载

private class Downloader extends Thread {
    private int threadId;
    private int startIndex;
    private int endIndex;

    public Downloader(int threadId, int startIndex, int endIndex) {
        this.threadId = threadId;
        this.startIndex = startIndex;
        this.endIndex = endIndex;
    }

    @Override
    public void run() {
        try {
            RandomAccessFile tempFile = new RandomAccessFile(tempFileName, "rwd");
            tempFile.seek(startIndex);
            InputStream inputStream = conn.getInputStream();
            inputStream.skip(startIndex);
            byte[] buffer = new byte[1024];
            int length;
            int downloadedBytes = 0;
            while ((length = inputStream.read(buffer)) != -1) {
                tempFile.write(buffer, 0, length);
                downloadedBytes += length;
                progress[threadId] = downloadedBytes;
            }
            inputStream.close();
            tempFile.close();
            Log.d(TAG, "Thread " + threadId + " download finished.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.6 下载完成后将文件保存到本地文件夹中

int downloadedBytes = 0;
for (int i = 0; i < THREAD_COUNT; i++) {
    downloadedBytes += progress[i];
}
if (downloadedBytes == totalSize) {
    File tempFile = new File(path, tempFileName);
    if (tempFile.exists()) {
        tempFile.renameTo(downloadedFile);
        Log.d(TAG, "Download finished!");
    }
}

3. 示例说明

3.1 示例一

假设要下载的文件是一个视频文件,大小为1GB,需要下载10个线程,文件保存在SD卡上,文件名为"video.mp4"。则可以使用以下代码实现:

String fileUrl = "http://yourdomain.com/path/to/video.mp4";
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = "video.mp4";
int THREAD_COUNT = 10;
String tempFileName = fileName + ".temp";
Downloader[] downloaders = new Downloader[THREAD_COUNT];
int[] progress = new int[THREAD_COUNT];

try {
    URL url = new URL(fileUrl);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("GET");
    conn.setConnectTimeout(5000);
    conn.setRequestProperty("Connection", "Keep-Alive");
    int totalSize = conn.getContentLength();
    File downloadedFile = new File(path, fileName);
    int downloadedSize = 0;
    if (downloadedFile.exists()) {
        downloadedSize = (int) downloadedFile.length();
    }
    if (downloadedSize < totalSize) {
        int blockSize = (totalSize + THREAD_COUNT - 1) / THREAD_COUNT;
        for (int threadId = 0; threadId < THREAD_COUNT; threadId++) {
            int startIndex = threadId * blockSize;
            int endIndex = startIndex + blockSize - 1;
            if (threadId == THREAD_COUNT - 1) {
                endIndex = totalSize - 1;
            }
            downloaders[threadId] = new Downloader(threadId, startIndex, endIndex);
            downloaders[threadId].start();
        }
    }
    int downloadedBytes = 0;
    for (int i = 0; i < THREAD_COUNT; i++) {
        downloaders[i].join();
        downloadedBytes += progress[i];
    }
    if (downloadedBytes == totalSize) {
        File tempFile = new File(path, tempFileName);
        if (tempFile.exists()) {
            tempFile.renameTo(downloadedFile);
            Log.d(TAG, "Download finished!");
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}

3.2 示例二

假设要下载的文件是一个图片文件,大小为100MB,需要下载5个线程,文件保存在应用私有目录上,文件名为"image.jpg"。则可以使用以下代码实现:

String fileUrl = "http://yourdomain.com/path/to/image.jpg";
String path = getFilesDir().getAbsolutePath();
String fileName = "image.jpg";
int THREAD_COUNT = 5;
String tempFileName = fileName + ".temp";
Downloader[] downloaders = new Downloader[THREAD_COUNT];
int[] progress = new int[THREAD_COUNT];

try {
    URL url = new URL(fileUrl);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("GET");
    conn.setConnectTimeout(5000);
    conn.setRequestProperty("Connection", "Keep-Alive");
    int totalSize = conn.getContentLength();
    File downloadedFile = new File(path, fileName);
    int downloadedSize = 0;
    if (downloadedFile.exists()) {
        downloadedSize = (int) downloadedFile.length();
    }
    if (downloadedSize < totalSize) {
        int blockSize = (totalSize + THREAD_COUNT - 1) / THREAD_COUNT;
        for (int threadId = 0; threadId < THREAD_COUNT; threadId++) {
            int startIndex = threadId * blockSize;
            int endIndex = startIndex + blockSize - 1;
            if (threadId == THREAD_COUNT - 1) {
                endIndex = totalSize - 1;
            }
            downloaders[threadId] = new Downloader(threadId, startIndex, endIndex);
            downloaders[threadId].start();
        }
    }
    int downloadedBytes = 0;
    for (int i = 0; i < THREAD_COUNT; i++) {
        downloaders[i].join();
        downloadedBytes += progress[i];
    }
    if (downloadedBytes == totalSize) {
        File tempFile = new File(path, tempFileName);
        if (tempFile.exists()) {
            tempFile.renameTo(downloadedFile);
            Log.d(TAG, "Download finished!");
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}

以上就是Android实现网络多线程文件下载的完整攻略,希望对大家有所帮助。

本文链接:http://task.lmcjl.com/news/9598.html

展开阅读全文