我正在开发一个应用程序,用户可以下载不同的内容包。 对于下载过程,我正在使用DownloadManager
类。 目前为止一切都很好。
我该如何获取已经通过DownloadManager
开始的正在运行的下载的当前进度。 我知道有内置的下载通知等等,但对我来说,必须获取正在运行的下载的进度,以便我可以在我的应用程序中使用它来显示自定义进度条中的进度。
这是否可能,还是我只是瞎了眼找不到解决方案。
我正在开发一个应用程序,用户可以下载不同的内容包。 对于下载过程,我正在使用DownloadManager
类。 目前为止一切都很好。
我该如何获取已经通过DownloadManager
开始的正在运行的下载的当前进度。 我知道有内置的下载通知等等,但对我来说,必须获取正在运行的下载的进度,以便我可以在我的应用程序中使用它来显示自定义进度条中的进度。
这是否可能,还是我只是瞎了眼找不到解决方案。
我也在寻找更好的方法,但目前打算每秒钟轮询一次以获取进度。
DownloadManager mgr = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
long id = mgr.enqueue(request);
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(id);
Cursor cursor = mgr.query(q);
cursor.moveToFirst();
int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
cursor.close();
编辑:
可以使用FileObserver
来实现这一点。以下是我编写的一个基础模板,可帮助跟踪应用程序已下载的文件。在活动或服务的onStart
中启动它并在onStop
中停止它。结合在onStart
期间对事物状态的手动同步,这可以让您对正在发生的情况有一个相当完整的了解。
特别是要实现进度,监听OPEN/CLOSE_WRITE事件可以帮助您决定何时开始/停止轮询DownloadManager以获取更新。
public class DownloadsObserver extends FileObserver {
public static final String LOG_TAG = DownloadsObserver.class.getSimpleName();
private static final int flags =
FileObserver.CLOSE_WRITE
| FileObserver.OPEN
| FileObserver.MODIFY
| FileObserver.DELETE
| FileObserver.MOVED_FROM;
// Received three of these after the delete event while deleting a video through a separate file manager app:
// 01-16 15:52:27.627: D/APP(4316): DownloadsObserver: onEvent(1073741856, null)
public DownloadsObserver(String path) {
super(path, flags);
}
@Override
public void onEvent(int event, String path) {
Log.d(LOG_TAG, "onEvent(" + event + ", " + path + ")");
if (path == null) {
return;
}
switch (event) {
case FileObserver.CLOSE_WRITE:
// Download complete, or paused when wifi is disconnected. Possibly reported more than once in a row.
// Useful for noticing when a download has been paused. For completions, register a receiver for
// DownloadManager.ACTION_DOWNLOAD_COMPLETE.
break;
case FileObserver.OPEN:
// Called for both read and write modes.
// Useful for noticing a download has been started or resumed.
break;
case FileObserver.DELETE:
case FileObserver.MOVED_FROM:
// These might come in handy for obvious reasons.
break;
case FileObserver.MODIFY:
// Called very frequently while a download is ongoing (~1 per ms).
// This could be used to trigger a progress update, but that should probably be done less often than this.
break;
}
}
}
用法应该像这样:
public class MyActivity extends Activity {
private FileObserver fileObserver = new DownloadsObserver(
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath());
@Override
protected void onStart() {
super.onStart();
fileObserver.startWatching();
syncUpDatabaseWithFileSystem();
}
@Override
protected void onStop() {
fileObserver.stopWatching();
super.onStop();
}
}
FileObserver
实现存在一个bug。因此,FileObserver
将不会报告下载管理器下载的文件的任何修改。(旧版Android没有这个问题——在KitKat上它可以正常工作。)来源
对我来说,以下代码(基于这个答案)运行良好。我每秒轮询一次——我尝试将间隔减半,但没有看到任何效果。private static final int PROGRESS_DELAY = 1000;
Handler handler = new Handler();
private boolean isProgressCheckerRunning = false;
// when the first download starts
startProgressChecker();
// when the last download finishes or the Activity is destroyed
stopProgressChecker();
/**
* Checks download progress.
*/
private void checkProgress() {
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterByStatus(~(DownloadManager.STATUS_FAILED | DownloadManager.STATUS_SUCCESSFUL));
Cursor cursor = downloadManager.query(query);
if (!cursor.moveToFirst()) {
cursor.close();
return;
}
do {
long reference = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_ID));
long progress = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
// do whatever you need with the progress
} while (cursor.moveToNext());
cursor.close();
}
/**
* Starts watching download progress.
*
* This method is safe to call multiple times. Starting an already running progress checker is a no-op.
*/
private void startProgressChecker() {
if (!isProgressCheckerRunning) {
progressChecker.run();
isProgressCheckerRunning = true;
}
}
/**
* Stops watching download progress.
*/
private void stopProgressChecker() {
handler.removeCallbacks(progressChecker);
isProgressCheckerRunning = false;
}
/**
* Checks download progress and updates status, then re-schedules itself.
*/
private Runnable progressChecker = new Runnable() {
@Override
public void run() {
try {
checkProgress();
// manager reference not found. Commenting the code for compilation
//manager.refresh();
} finally {
handler.postDelayed(progressChecker, PROGRESS_DELAY);
}
}
};
FileObserver#onEvent()
在单独的线程上运行。对于任何UI操作(例如更新进度条),您需要执行类似new Handler(Looper.getMainLooper())。post(new Runnable(){...});
这样的操作,并将代码放置在Runnable
的run()
方法中。 - user149408