Mostra l'avanzamento del download all'interno dell'attività utilizzando DownloadManager


89

Sto cercando di riprodurre lo stesso progresso che DownloadManager mostra nella barra delle notifiche all'interno della mia app, ma i miei progressi non vengono mai pubblicati. Sto cercando di aggiornarlo usando runOnUiThread (), ma per qualche motivo non è stato aggiornato.

il mio download:

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

il mio metodo 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);
}

Il mio registro funziona perfettamente, mentre il download è in esecuzione dice "Download in corso!" e quando è completo "Download completato!", ma lo stesso non accade sui miei progressi, perché? Ho davvero bisogno di aiuto, altre logiche per farlo sono davvero apprezzate


Potrebbe essere che il tuo file sia semplicemente troppo piccolo e che il download venga completato prima della pubblicazione dell'avanzamento? Cosa restituisce la query di download nella tua attività? Se l'attività viene eseguita solo dopo un certo periodo di tempo, potresti avere qualche altra operazione di lunga durata sul thread principale.
Paul Lammertsma

Ho aggiornato il codice, puoi dare un'occhiata adesso? E riguardo alla lunghezza del file non è troppo piccola, posso vedere l'avanzamento del download sulla barra delle notifiche
Victor Laerte

Risposte:


62

Stai dividendo due numeri interi:

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

Poiché bytes_downloadedè minore di bytes_total, (bytes_downloaded / bytes_total)sarà 0 e il tuo progresso sarà quindi sempre 0.

Cambia il tuo calcolo in

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

per ottenere il progresso in percentili interi (anche se limitati).


@AZ_ Grazie per il tuo contributo. Ti suggerirei di aggiungere la tua risposta con la soluzione più elaborata.
Paul Lammertsma

Va bene non voglio mettere un'altra risposta di risposta già accettata perché sarà difficile per gli utenti. Puoi scegliere di non accettare la mia modifica :)
AZ_

1
Se la tua attività termina e desideri annullare il download, riceverai un division by zeroerrore irreversibile. Ecco perché l'ho fatto come final int dl_progress = ( bytes_total > 0 ? (int) ((bytes_downloaded * 100L) / bytes_total) : 0 );
KaHa6uc

17

La risposta di Paul è corretta, ma con download più grandi raggiungerai il massimo int abbastanza rapidamente e inizierai a ottenere un progresso negativo. L'ho usato per risolvere il problema:

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

Hai ragione; Ho modificato la mia risposta per assicurarmi che gli altri non commettano lo stesso errore.
Paul Lammertsma,

4

Come ha detto paul, stai dividendo due numeri interi, con risultato sempre <1.

Trasmetti sempre il tuo numero prima divisione, che calcola e restituisce in virgola mobile.

Non dimenticare di gestire DivByZero.

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

4

Nel caso in cui qualcuno avesse bisogno di implementare il download progress retriever dalla domanda di @Victor Laerte in Kotlin con RxJava, ecco qui:

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

Ho aggiunto estensioni al cursore per una maggiore chiarezza del codice:

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))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.