Hiển thị tiến trình Tải xuống bên trong hoạt động bằng DownloadManager


89

Tôi đang cố gắng tái tạo cùng một tiến trình mà DownloadManager hiển thị trong thanh Thông báo bên trong ứng dụng của mình, nhưng tiến trình của tôi không bao giờ được xuất bản. Tôi đang cố gắng cập nhật nó bằng runOnUiThread (), nhưng vì một số lý do mà nó không được cập nhật.

tải xuống của tôi:

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

trạng thái của tôi Phương thức tin nhắn:

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

Nhật ký của tôi đang hoạt động hoàn hảo, trong khi quá trình tải xuống của tôi đang chạy có thông báo "Đang tải xuống!" và khi nó hoàn tất "Tải xuống hoàn tất!", nhưng điều tương tự không xảy ra với tiến trình của tôi, tại sao? Tôi thực sự cần một số trợ giúp, các logic khác để làm điều đó thực sự được đánh giá cao


Có thể do tệp của bạn quá nhỏ và quá trình tải xuống hoàn tất trước khi tiến trình được xuất bản? Truy vấn tải xuống trả lại gì trong nhiệm vụ của bạn? Nếu tác vụ chỉ được thực thi sau một khoảng thời gian, bạn có thể có một số hoạt động lâu dài khác trên luồng chính của mình.
Paul Lammertsma

Tôi đã cập nhật mã, bạn có thể xem ngay bây giờ? Và về chiều dài của tệp, nó không quá nhỏ, tôi có thể thấy tiến trình tải xuống trên thanh thông báo
Victor Laerte

Câu trả lời:


62

Bạn đang chia hai số nguyên:

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

Như bytes_downloadednhỏ hơn bytes_total, (bytes_downloaded / bytes_total)sẽ là 0, và tiến trình của bạn do đó sẽ luôn là 0.

Thay đổi phép tính của bạn thành

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

để có được sự tiến bộ trong toàn bộ (mặc dù được phân tầng).


@AZ_ Cảm ơn sự đóng góp của bạn. Tôi khuyên bạn nên thêm câu trả lời của riêng mình với giải pháp phức tạp hơn.
Paul Lammertsma

Được rồi, tôi không muốn đặt một câu trả lời khác của câu trả lời đã được chấp nhận vì nó sẽ khó cho người dùng. Bạn có thể chọn không chấp nhận chỉnh sửa của tôi :)
AZ_ Ngày

1
Nếu hoạt động của bạn kết thúc và bạn muốn hủy tải xuống, bạn sẽ gặp phải division by zerolỗi nghiêm trọng. Đó là lý do tại sao tôi đã làm điều đó như final int dl_progress = ( bytes_total > 0 ? (int) ((bytes_downloaded * 100L) / bytes_total) : 0 );
KaHa6uc

17

Câu trả lời của Paul là đúng nhưng với lượt tải xuống lớn hơn, bạn sẽ đạt mức tối đa khá nhanh và bắt đầu nhận được một tiến bộ tiêu cực. Tôi đã sử dụng điều này để giải quyết vấn đề:

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

Bạn đúng rồi; Tôi đã sửa đổi câu trả lời của mình để đảm bảo những người khác không mắc lỗi tương tự.
Paul Lammertsma

4

Như paul đã nói, bạn đang chia hai số nguyên, với kết quả luôn <1.

Luôn sử dụng số của bạn trước khi chia, số này sẽ tính toán và trả về trong dấu phẩy động.

Đừng quên xử lý DivByZero.

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

4

Trong trường hợp nếu ai đó cần triển khai trình truy xuất tiến trình tải xuống từ câu hỏi của @Victor Laerte trong Kotlin với RxJava thì bạn hãy truy cập:

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

Tôi đã thêm tiện ích mở rộng vào con trỏ để mã rõ ràng hơn:

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))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.