Tampilkan kemajuan Download di dalam aktivitas menggunakan DownloadManager

90

Saya mencoba mereproduksi kemajuan yang sama yang ditunjukkan DownloadManager di bilah Pemberitahuan di dalam aplikasi saya, tetapi kemajuan saya tidak pernah dipublikasikan. Saya mencoba memperbaruinya menggunakan runOnUiThread (), tetapi untuk beberapa alasan itu belum diperbarui.

unduhan saya:

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

metode statusMessage saya:

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

Log saya bekerja dengan sempurna, saat unduhan saya berjalan, bertuliskan "Unduhan sedang berlangsung!" dan setelah selesai "Download selesai!", tetapi hal yang sama tidak terjadi pada kemajuan saya, mengapa? Saya benar-benar membutuhkan bantuan, logika lain untuk melakukan itu sangat dihargai

Victor Laerte
sumber
Mungkinkah file Anda terlalu kecil, dan unduhan selesai sebelum kemajuannya dipublikasikan? Apa yang dikembalikan kueri unduhan dalam tugas Anda? Jika tugas hanya dijalankan setelah beberapa periode waktu, Anda mungkin memiliki beberapa operasi lain yang berjalan lama di thread utama Anda.
Paul Lammertsma
Saya telah memperbarui kodenya, dapatkah Anda melihatnya sekarang? Dan tentang panjang file tidak terlalu kecil, saya dapat melihat kemajuan unduhan di bilah notifikasi
Victor Laerte

Jawaban:

62

Anda membagi dua bilangan bulat:

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

As bytes_downloadedkurang dari bytes_total, (bytes_downloaded / bytes_total)akan menjadi 0, dan karena itu kemajuan Anda akan selalu 0.

Ubah perhitungan Anda menjadi

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

untuk mendapatkan kemajuan dalam persentil keseluruhan (meskipun berlantai).

Paul Lammertsma
sumber
@AZ_ Terima kasih atas kontribusi Anda. Saya sarankan Anda menambahkan jawaban Anda sendiri dengan solusi yang lebih rumit.
Paul Lammertsma
Tidak apa-apa saya tidak ingin meletakkan jawaban lain dari jawaban yang sudah diterima karena akan menyulitkan pengguna. Anda dapat memilih untuk tidak menerima suntingan saya :)
AZ_
1
Jika aktivitas Anda berakhir dan Anda ingin membatalkan download, Anda akan mendapatkan division by zeroerror yang fatal. Itulah mengapa saya melakukannya seperti final int dl_progress = ( bytes_total > 0 ? (int) ((bytes_downloaded * 100L) / bytes_total) : 0 );
KaHa6uc
17

Jawaban Paul benar tetapi dengan unduhan yang lebih besar Anda akan mencapai max int dengan cukup cepat dan mulai mendapatkan kemajuan negatif. Saya menggunakan ini untuk menyelesaikan masalah:

final int dl_progress = (int) ((bytes_downloaded * 100l) / bytes_total);
JustinMorris
sumber
Kamu benar; Saya telah mengubah jawaban saya untuk memastikan orang lain tidak melakukan kesalahan yang sama.
Paul Lammertsma
4

Seperti yang dikatakan paul, Anda membagi dua bilangan bulat, dengan hasil selalu <1.

Selalu berikan bilangan Anda sebelum membagi, yang menghitung dan mengembalikan dalam titik-mengambang.

Jangan lupa untuk menangani DivByZero.

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

Jika seseorang membutuhkan implementasi download progress retriever dari pertanyaan @Victor Laerte di Kotlin dengan RxJava ini dia:

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

Saya telah menambahkan ekstensi ke kursor agar kode lebih jelas:

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
sumber