Afficher la progression du téléchargement dans l'activité à l'aide de DownloadManager

89

J'essaie de reproduire la même progression que celle de DownloadManager dans la barre de notification de mon application, mais ma progression n'est jamais publiée. J'essaie de le mettre à jour en utilisant runOnUiThread (), mais pour une raison quelconque, il n'a pas été mis à jour.

mon téléchargement:

String urlDownload = "https://dl.dropbox.com/s/ex4clsfmiu142dy/test.zip?token_hash=AAGD-XcBL8C3flflkmxjbzdr7_2W_i6CZ_3rM5zQpUCYaw&dl=1";
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(urlDownload));

request.setDescription("Testando");
request.setTitle("Download");
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "teste.zip");

final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);

final long downloadId = manager.enqueue(request);

final ProgressBar mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);

new Thread(new Runnable() {

    @Override
    public void run() {

        boolean downloading = true;

        while (downloading) {

            DownloadManager.Query q = new DownloadManager.Query();
            q.setFilterById(downloadId);

            Cursor cursor = manager.query(q);
            cursor.moveToFirst();
            int bytes_downloaded = cursor.getInt(cursor
                    .getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
            int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));

            if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
                downloading = false;
            }

            final double dl_progress = (bytes_downloaded / bytes_total) * 100;

            runOnUiThread(new Runnable() {

                @Override
                public void run() {

                    mProgressBar.setProgress((int) dl_progress);

                }
            });

            Log.d(Constants.MAIN_VIEW_ACTIVITY, statusMessage(cursor));
            cursor.close();
        }

    }
}).start();

ma méthode statusMessage:

private String statusMessage(Cursor c) {
    String msg = "???";

    switch (c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS))) {
    case DownloadManager.STATUS_FAILED:
        msg = "Download failed!";
        break;

    case DownloadManager.STATUS_PAUSED:
        msg = "Download paused!";
        break;

    case DownloadManager.STATUS_PENDING:
        msg = "Download pending!";
        break;

    case DownloadManager.STATUS_RUNNING:
        msg = "Download in progress!";
        break;

    case DownloadManager.STATUS_SUCCESSFUL:
        msg = "Download complete!";
        break;

    default:
        msg = "Download is nowhere in sight";
        break;
    }

    return (msg);
}

Mon journal fonctionne parfaitement, tandis que mon téléchargement est en cours d'exécution dit "Téléchargement en cours!" et quand il est terminé "Téléchargement terminé!", mais que la même chose ne se produit pas sur ma progression, pourquoi? J'ai vraiment besoin d'aide, d'autres logiques à faire qui sont vraiment appréciées

Victor Laerte
la source
Se pourrait-il que votre fichier soit simplement trop petit et que le téléchargement se termine avant la publication de la progression? Que renvoie la requête de téléchargement dans votre tâche? Si la tâche n'est exécutée qu'après un certain temps, vous pouvez avoir une autre opération de longue durée sur votre thread principal.
Paul Lammertsma
J'ai mis à jour le code, pouvez-vous jeter un œil maintenant? Et à propos de la longueur du fichier, il n'est pas trop petit, je peux voir la progression du téléchargement sur la barre de notification
Victor Laerte

Réponses:

62

Vous divisez deux entiers:

final double dl_progress = (bytes_downloaded / bytes_total) * 100;

As bytes_downloadedest inférieur à bytes_total, (bytes_downloaded / bytes_total)sera 0, et votre progression sera donc toujours 0.

Modifiez votre calcul en

final int dl_progress = (int) ((bytes_downloaded * 100l) / bytes_total);

pour obtenir la progression en percentiles entiers (quoique plancher).

Paul Lammertsma
la source
@AZ_ Merci pour votre contribution. Je vous suggère d'ajouter votre propre réponse avec la solution la plus élaborée.
Paul Lammertsma
C'est ok, je ne veux pas mettre une autre réponse de réponse déjà acceptée car ce sera difficile pour les utilisateurs. Vous pouvez choisir de ne pas accepter ma modification :)
AZ_
1
Si votre activité se termine et que vous souhaitez annuler le téléchargement, vous obtiendrez une division by zeroerreur fatale. C'est pourquoi je l'ai fait comme final int dl_progress = ( bytes_total > 0 ? (int) ((bytes_downloaded * 100L) / bytes_total) : 0 );
KaHa6uc
17

La réponse de Paul est correcte, mais avec des téléchargements plus importants, vous atteindrez max int assez rapidement et commencerez à obtenir une progression négative. J'ai utilisé ceci pour résoudre le problème:

final int dl_progress = (int) ((bytes_downloaded * 100l) / bytes_total);
JustinMorris
la source
Vous avez raison; J'ai modifié ma réponse pour m'assurer que les autres ne font pas la même erreur.
Paul Lammertsma
4

Comme Paul l'a dit, vous divisez deux entiers, avec un résultat toujours <1.

Cast toujours votre nombre avant la division, qui calcule et retourne en virgule flottante.

N'oubliez pas de gérer DivByZero.

final int dl_progress = (int) ((double)bytes_downloaded / (double)bytes_total * 100f);
Dennis C
la source
4

Si quelqu'un a besoin de l'implémentation du récupérateur de progression du téléchargement à partir de la question de @Victor Laerte dans Kotlin avec RxJava, allez-y:

DownloadStateRetriever.kt

class DownloadStateRetriever(private val downloadManager: DownloadManager) {

    fun retrieve(id: Long) {
        var downloading = AtomicBoolean(true)

        val disposable = Observable.fromCallable {
            val query = DownloadManager.Query().setFilterById(id)
            val cursor = downloadManager.query(query)

            cursor.moveToFirst()

            val bytesDownloaded = cursor.intValue(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)
            val bytesTotal = cursor.intValue(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)

            if (isSuccessful(cursor)) downloading.set(false)
            cursor.close()

            if (bytesTotal == 0) 0.toInt() else ((bytesDownloaded * 100F) / bytesTotal).toInt()
        }
                .subscribeOn(Schedulers.newThread())
                .delay(1, TimeUnit.SECONDS)
                .repeatUntil { !downloading.get() }
                .subscribe {
                    Timber.i("Subscribed to $id. progress: $it")
                }
    }

    private fun isSuccessful(cursor: Cursor) = status(cursor) == DownloadManager.STATUS_SUCCESSFUL

    private fun status(cursor: Cursor) = cursor.intValue(DownloadManager.COLUMN_STATUS)
}

J'ai ajouté des extensions au curseur pour plus de clarté du code:

CursorExtensions.kt

import android.database.Cursor

fun Cursor.column(which: String) = this.getColumnIndex(which)
fun Cursor.intValue(which: String): Int = this.getInt(column(which))
fun Cursor.floatValue(which: String): Float = this.getFloat(column(which))
fun Cursor.stringValue(which: String): String = this.getString(column(which))
fun Cursor.doubleValue(which: String): Double = this.getDouble(column(which))
rahimli
la source