Android的DownloadManager进度
我正在开发一个应用程序,用户可以下载不同的内容包。 对于下载过程,我正在使用DownloadManager类。 这到目前为止工作得很好。
我的问题是我怎么能得到一个正在运行的下载,这是开始与下载pipe理器的当前进度。 我知道有build立在下载通知等。 但对我来说,我需要获得正在运行的下载的进度,以便我可以使用它来显示我的应用程序中的自定义进度栏中的进度。 到目前为止,我无法检索进度。
这是可能的,或者我只是盲目的,找不到解决scheme。
希望有人能帮助我…
我正在寻找一个更好的方法来做到这一点,但到目前为止,我打算每隔1秒左右轮询一次进度。
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(); } }
事实certificate,Marshmallow上的FileObserver
实现有一个bug。 因此, FileObserver
不会报告下载pipe理器下载的文件的任何修改。 (较旧的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 = ursor.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.refresh(); } finally { handler.postDelayed(progressChecker, PROGRESS_DELAY); } } };