一、使用线程池分段下载,然后再合并文件
public class Main {
private static final String url = "https://d9f43c992961ae0750505398dbb4823c.dd.cdntips.com/imtt.dd.qq.com/16891/apk/9C52689F0451CBFBDBBF535ADD40D3A7.apk?mkey=5e9fdcc9777b5f80&f=24c3&fsname=com.tencent.weishi_6.7.6.588_676.apk&csr=1bbd&cip=119.123.121.117&proto=https";
public static void main(String[] args) throws IOException {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
conn.setRequestProperty("connection", "keep-alive");
int fileLength = conn.getContentLength();
System.out.println("文件长度:" + fileLength);
int theadCount = 3;
int size = fileLength / theadCount;
System.out.println("每个下载量:" + size);
conn.disconnect();
File file = new File("D:\\ws.apk");
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
MyTask task0 = new MyTask(0, 0, size - 1, file);
MyTask task1 = new MyTask(1, size, (2 * size) - 1, file);
MyTask task2 = new MyTask(2, 2 * size, fileLength, file);
fixedThreadPool.execute(task0);
fixedThreadPool.execute(task1);
fixedThreadPool.execute(task2);
fixedThreadPool.shutdown();
}
static class MyTask implements Runnable {
private final int taskNum;
private final int startPos;
private final int endPos;
private final File file;
public MyTask(int taskNum, int startPos, int endPos, File file) {
this.taskNum = taskNum;
this.startPos = startPos;
this.endPos = endPos;
this.file = file;
}
@Override
public void run() {
try {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
conn.setRequestProperty("connection", "keep-alive");
//设置下载区间
conn.setRequestProperty("range", "bytes=" + startPos + "-" + endPos);
conn.connect();
int code = conn.getResponseCode();
if (code == 206) {
InputStream in = conn.getInputStream();
int serverSize = conn.getContentLength();
System.out.println("服务器返回的长度:" + serverSize);
System.out.println("bytes=" + startPos + "-" + endPos);
System.out.println(Thread.currentThread().getName() + "---" + taskNum);
RandomAccessFile out = new RandomAccessFile(file, "rw");
out.seek(startPos);
byte[] b = new byte[1024];
int len = -1;
while ((len = in.read(b)) != -1) {
out.write(b, 0, len);
}
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
二、使用android自带的DownloadManager下载更新apk
val downloadManager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
val request = DownloadManager.Request(Uri.parse(apkUrl))
//指定WiFi下才下载
//request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI)
//指定MOBILE状态下才下载
//request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE)
//是否允许漫游下下载
//request.setAllowedOverRoaming(false)
//是否允许 计量式网络连接 下载
//request.setAllowedOverMetered(true)//默认为true
//取消下载(如果下载被取消,所下文件会被删除)
//downloadManager.remove(id)
//显示还是隐藏
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
//设置notification的标题和描述
request.setTitle("下载文件标题")
request.setDescription("下载文件描述")
//设置下载文件类型
request.setMimeType("application/vnd.android.package-archive")
//请求头等信息
//request.addRequestHeader("","")
//保存文件路径,当前应用目录下file/downloads
request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, "demo.apk")
var id: Long = 0
button.setOnClickListener {
//每下载一个文件对应一个id,通过id可以查询数据
id = downloadManager.enqueue(request)
}
//使用handler和Timer更新进度条
val handler = @SuppressLint("HandlerLeak")
object : Handler() {
@SuppressLint("HandlerLeak")
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
val progress = msg.data.getInt("pro")
bar.progress = progress
}
}
val timer = Timer()
val task = object : TimerTask() {
override fun run() {
val cursor = downloadManager.query(DownloadManager.Query().setFilterById(id))
if (cursor != null && cursor.moveToFirst()) {
//获取下载状态信息
if (cursor.getInt(
cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
) == DownloadManager.STATUS_SUCCESSFUL
) {
//下载完成
bar.progress = 100
cancel()
timer.cancel()
}
val title =
cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE))
val url =
cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))
val current =
cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
val total =
cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
val pro = current * 100 / total
val msg: Message = Message.obtain()
val bundle = Bundle()
bundle.putInt("pro", pro)
bundle.putString("name", title)
msg.data = bundle
handler.sendMessage(msg)
}
cursor?.close()
}
}
timer.schedule(task, 0, 1000)