文件下载恢复到单线程

This commit is contained in:
frank wang 2025-10-31 10:10:18 +08:00
parent 569c025169
commit f5d1e9b98d
1 changed files with 74 additions and 108 deletions

View File

@ -246,136 +246,102 @@ public class FirstActivity extends BaseActivity {
// || url.contains("/api/file/"); // || url.contains("/api/file/");
} }
private long currentDownloadId = -1; // 保存当前下载任务ID private long currentDownloadId = -1; // 保存当前下载任务ID
/**
* 下载文件并调用系统 DownloadManager
*/
private void downloadFile(String url) { private void downloadFile(String url) {
new Thread(() -> { try {
try { if (TextUtils.isEmpty(url)) {
if (TextUtils.isEmpty(url)) { Toast.makeText(this, "下载地址为空", Toast.LENGTH_SHORT).show();
handler.post(() -> return;
Toast.makeText(this, "下载地址为空", Toast.LENGTH_SHORT).show()
);
return;
}
if (url.startsWith("blob:") || url.startsWith("data:")) {
handler.post(() ->
Toast.makeText(this, "无法直接下载 Blob 文件,请检查前端下载逻辑", Toast.LENGTH_SHORT).show()
);
return;
}
Uri uri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(uri);
String fileName = URLUtil.guessFileName(url, null, null);
request.setTitle(fileName);
request.setDescription("正在下载文件...");
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
request.allowScanningByMediaScanner();
request.addRequestHeader("User-Agent", System.getProperty("http.agent"));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
request.setRequiresCharging(false);
request.setAllowedOverMetered(true);
request.setAllowedOverRoaming(true);
}
String mimeType = getMimeTypeForUrl(url);
request.setMimeType(!TextUtils.isEmpty(mimeType) ? mimeType : "application/octet-stream");
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
if (dm != null) {
handler.post(() ->
Toast.makeText(this, "文件已开始下载,请等待", Toast.LENGTH_SHORT).show()
);
currentDownloadId = dm.enqueue(request);
startDownloadProgressMonitor(dm, currentDownloadId);
} else {
handler.post(() ->
Toast.makeText(this, "系统下载服务不可用", Toast.LENGTH_SHORT).show()
);
}
} catch (Exception e) {
e.printStackTrace();
handler.post(() ->
Toast.makeText(this, "下载失败: " + e.getMessage(), Toast.LENGTH_SHORT).show()
);
} }
}).start();
if (url.startsWith("blob:") || url.startsWith("data:")) {
Toast.makeText(this, "无法直接下载 Blob 文件,请检查前端下载逻辑", Toast.LENGTH_SHORT).show();
return;
}
Uri uri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(uri);
String fileName = URLUtil.guessFileName(url, null, null);
request.setTitle(fileName);
request.setDescription("正在下载文件...");
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
request.allowScanningByMediaScanner();
request.addRequestHeader("User-Agent", System.getProperty("http.agent"));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
request.setRequiresCharging(false);
request.setAllowedOverMetered(true);
request.setAllowedOverRoaming(true);
}
String mimeType = getMimeTypeForUrl(url);
request.setMimeType(!TextUtils.isEmpty(mimeType) ? mimeType : "application/octet-stream");
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
if (dm != null) {
Toast.makeText(this, "文件已开始下载,请等待", Toast.LENGTH_SHORT).show();
currentDownloadId = dm.enqueue(request);
startDownloadProgressMonitor(dm, currentDownloadId);
} else {
Toast.makeText(this, "系统下载服务不可用", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "下载失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
} }
/** /**
* 监控下载进度每秒回调一次到前端 * 监控下载进度每秒回调一次到前端
*/ */
private void startDownloadProgressMonitor(DownloadManager dm, long downloadId) { private void startDownloadProgressMonitor(DownloadManager dm, long downloadId) {
new Thread(() -> {
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadId);
boolean downloading = true;
while (downloading) { DownloadManager.Query query = new DownloadManager.Query();
try { query.setFilterById(downloadId);
Thread.sleep(1000); boolean downloading = true;
android.database.Cursor cursor = dm.query(query);
if (cursor != null && cursor.moveToFirst()) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
long total = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
long downloaded = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
if (status == DownloadManager.STATUS_RUNNING && total > 0) { while (downloading) {
int progress = (int) ((downloaded * 100L) / total); try {
handler.post(() -> { Thread.sleep(1000);
sendProgressToJs(progress); android.database.Cursor cursor = dm.query(query);
// 可选减少 toast 频率比如每 20% 提示一次 if (cursor != null && cursor.moveToFirst()) {
if (progress % 20 == 0) { int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
Toast.makeText(this, "下载中:" + progress + "%", Toast.LENGTH_SHORT).show(); long total = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
} long downloaded = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
}); if (status == DownloadManager.STATUS_RUNNING && total > 0) {
} else if (status == DownloadManager.STATUS_SUCCESSFUL) { int progress = (int) ((downloaded * 100L) / total);
downloading = false; Toast.makeText(this, "下载中,当前进度为" + progress + "%", Toast.LENGTH_SHORT).show();
handler.post(() -> { handler.post(() -> sendProgressToJs(progress));
sendProgressToJs(100); } else if (status == DownloadManager.STATUS_SUCCESSFUL) {
Toast.makeText(this, "下载完成,请到文件管理查看", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "下载完成,请到文件管理查看", Toast.LENGTH_SHORT).show();
}); downloading = false;
} else if (status == DownloadManager.STATUS_FAILED) { handler.post(() -> sendProgressToJs(100));
downloading = false; } else if (status == DownloadManager.STATUS_FAILED) {
handler.post(() -> { Toast.makeText(this, "下载失败" + status + "," + total + "," + downloaded, Toast.LENGTH_SHORT).show();
sendProgressToJs(-1); downloading = false;
Toast.makeText(this, "下载失败", Toast.LENGTH_SHORT).show(); handler.post(() -> sendProgressToJs(-1));
});
}
cursor.close();
} }
} catch (Exception e) { cursor.close();
e.printStackTrace();
downloading = false;
handler.post(() ->
Toast.makeText(this, "监控异常:" + e.getMessage(), Toast.LENGTH_SHORT).show()
);
} }
} catch (Exception ignored) {
Toast.makeText(this, "文件已开始下载,请等待报错", Toast.LENGTH_SHORT).show();
} }
}).start(); }
} }
/**
* 向前端回调进度
*/
private void sendProgressToJs(int progress) { private void sendProgressToJs(int progress) {
try { try {
if (webView != null) { if (webView != null) {
String js = String.format("if(window.onDownloadProgress){window.onDownloadProgress(%d);}", progress); String js = String.format("if(window.onDownloadProgress){window.onDownloadProgress(%d);}", progress);
webView.evaluateJavascript(js, null); webView.evaluateJavascript(js, null);
} }
} catch (Exception e) { } catch (Exception ignored) {
e.printStackTrace(); Toast.makeText(this, "文件已开始下载请等待报错sendProgressToJs", Toast.LENGTH_SHORT).show();
handler.post(() ->
Toast.makeText(this, "进度回调异常:" + e.getMessage(), Toast.LENGTH_SHORT).show()
);
} }
} }