web-dev-qa-db-fra.com

Android Progression de DownloadManager

je développe une application où les utilisateurs peuvent télécharger différents packages de contenu. Pour le processus de téléchargement, j'utilise la classe DownloadManager. Cela fonctionne bien jusqu'à présent.

Ma question est de savoir comment obtenir la progression actuelle d'un téléchargement en cours qui a été lancé avec le DownloadManager. Je sais qu'il y a la notification de téléchargement de buildin et ainsi de suite. Mais pour moi, il est nécessaire que j'obtienne la progression du téléchargement en cours afin que je puisse l'utiliser pour afficher la progression dans une barre de progression personnalisée dans mon application. Jusqu'à présent, je n'ai pas pu récupérer les progrès.

Est-ce même possible ou suis-je simplement aveugle et ne trouve pas la solution.

J'espère que quelqu'un pourra m'aider ...

39
user1003622

Je suis à la recherche d'une meilleure façon de le faire également, mais jusqu'à présent, je prévois de simplement interroger les progrès toutes les 1 seconde environ.

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();

Modifier:

Un FileObserver peut vous aider. C'est le squelette de celui que j'ai rassemblé pour aider à garder une trace des fichiers téléchargés par notre application. Démarrez-le dans une activité ou un service onStart et arrêtez-le dans onStop. Combiné avec une synchronisation manuelle de l'état des choses pendant onStart, cela peut vous donner une image assez complète de ce qui se passe.

Pour progresser en particulier, la surveillance des événements OPEN/CLOSE_WRITE peut vous aider à décider quand démarrer/arrêter l'interrogation du DownloadManager pour les mises à jour.

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;
        }
    }
}

L'utilisation serait quelque chose comme ceci:

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();
    }
}
37
dokkaebi

Il s'avère que l'implémentation FileObserver sur Marshmallow a un bug. Par conséquent, FileObserver ne signalera aucune modification d'un fichier téléchargé par le gestionnaire de téléchargement. (Les anciennes versions Android n'ont pas ce problème - cela fonctionne très bien sur KitKat.) Source

Pour moi, le code suivant (basé sur cette réponse ) fonctionne bien. Je scrute chaque seconde - j'ai essayé de diviser cet intervalle par deux, mais sans aucun effet visible.

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);
        }
    }
};
2
user149408