Android的多线程网络下载的工具类
在这个代码中:
MultiThreadDownloader
类是主要的下载类。构造函数接受要下载文件的 URL、保存文件的路径以及下载线程的数量。- 在
download
方法中,首先获取文件的总大小,创建保存文件(如果不存在),然后计算每个线程需要下载的文件大小范围。 - 每个
DownloadTask
表示一个下载线程的任务,它通过设置Range
请求头来请求文件的一部分进行下载。下载完成后,通过CountDownLatch
来协调所有线程完成下载任务。 - 在
MainActivity
中的示例代码演示了如何创建MultiThreadDownloader
类并启动下载过程。
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MultiThreadDownloader {
private static final String TAG = "MultiThreadDownloader";
private static final int BUFFER_SIZE = 8192;
private String urlStr;
private String saveFilePath;
private int threadNum;
public MultiThreadDownloader(String urlStr, String saveFilePath, int threadNum) {
this.urlStr = urlStr;
this.saveFilePath = saveFilePath;
this.threadNum = threadNum;
}
public void download() {
try {
URL url = new URL(urlStr);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
int fileLength = connection.getContentLength();
File file = new File(saveFilePath);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.setLength(fileLength);
raf.close();
int partLength = fileLength / threadNum;
CountDownLatch latch = new CountDownLatch(threadNum);
ExecutorService executor = Executors.newFixedThreadPool(threadNum);
for (int i = 0; i < threadNum; i++) {
long start = i * partLength;
long end = (i == threadNum - 1)? fileLength - 1 : (i + 1) * partLength - 1;
DownloadTask task = new DownloadTask(start, end, latch);
executor.execute(task);
}
latch.await();
executor.shutdown();
Log.d(TAG, "Download completed.");
} catch (IOException | InterruptedException e) {
Log.e(TAG, "Download error: " + e.getMessage());
}
}
private class DownloadTask implements Runnable {
private long start;
private long end;
private CountDownLatch latch;
public DownloadTask(long start, long end, CountDownLatch latch) {
this.start = start;
this.end = end;
this.latch = latch;
}
@Override
public void run() {
try {
URL url = new URL(urlStr);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Range", "bytes=" + start + "-" + end);
connection.connect();
InputStream inputStream = connection.getInputStream();
File file = new File(saveFilePath);
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.seek(start);
byte[] buffer = new byte[BUFFER_SIZE];
int length;
while ((length = inputStream.read(buffer))!= -1) {
raf.write(buffer, 0, length);
}
raf.close();
inputStream.close();
Log.d(TAG, "Thread finished downloading its part.");
latch.countDown();
} catch (IOException e) {
Log.e(TAG, "Thread download error: " + e.getMessage());
}
}
}
}
以下是使用示例:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String url = "http://example.com/your_file.zip";
String savePath = getExternalFilesDir(null).getAbsolutePath() + "/your_file.zip";
int threadCount = 3;
MultiThreadDownloader downloader = new MultiThreadDownloader(url, savePath, threadCount);
downloader.download();
}
}
请注意:
- 这只是一个简单的示例,实际应用中可能需要更多的错误处理,例如处理网络连接失败、服务器错误等。
- 在 Android 6.0 及以上版本,可能需要处理运行时权限,特别是当保存文件到外部存储时。