Android DownloadManager Progress - PullRequest
       6

Android DownloadManager Progress

37 голосов
/ 19 октября 2011

Я занимаюсь разработкой приложения, в котором пользователи могут загружать различные пакеты контента. Для процесса загрузки я использую класс DownloadManager. Это работает нормально до сих пор.

Мой вопрос: как мне узнать текущее состояние текущей загрузки, которая была запущена с помощью DownloadManager? Я знаю, что есть встроенное уведомление о загрузке и так далее. Но для меня необходимо, чтобы я получил прогресс текущей загрузки, чтобы я мог использовать его для отображения прогресса в пользовательском индикаторе прогресса в моем приложении. До сих пор я не смог получить прогресс.

Возможно ли это или я просто слеп и не могу найти решение?

Надеюсь, кто-нибудь сможет мне помочь ...

Ответы [ 2 ]

37 голосов
/ 04 ноября 2011

Я также ищу лучший способ сделать это, но пока я планирую просто опрашивать прогресс каждые 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();

Редактировать:

A 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();
    }
}
2 голосов
/ 14 июня 2016

Оказывается, что реализация FileObserver в Marshmallow имеет ошибку. В результате 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);
        }
    }
};
...