DownloadWorker: Better handle individual file progress updates

* Don't filter InputStream updates as we are already guarding UI updates against total progress
* Update downloadedBytes based on bytesCopied to reflect real progress
* Use collect instead of collectLatest to ensure all updates from flow are handled

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2024-05-06 12:58:59 +05:30
parent 855bb1dbc8
commit 00532f200e
2 changed files with 7 additions and 11 deletions

View File

@@ -7,7 +7,6 @@ import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import java.io.InputStream import java.io.InputStream
import java.io.OutputStream import java.io.OutputStream
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlin.concurrent.fixedRateTimer import kotlin.concurrent.fixedRateTimer
fun InputStream.copyTo(out: OutputStream, streamSize: Long): Flow<DownloadInfo> { fun InputStream.copyTo(out: OutputStream, streamSize: Long): Flow<DownloadInfo> {
@@ -29,9 +28,9 @@ fun InputStream.copyTo(out: OutputStream, streamSize: Long): Flow<DownloadInfo>
out.write(buffer, 0, bytes) out.write(buffer, 0, bytes)
bytesCopied += bytes bytesCopied += bytes
// Emit stream progress in percentage // Emit stream progress in percentage
emit(DownloadInfo((bytesCopied * 100 / streamSize).toInt(), bytesCopied, speed)) emit(DownloadInfo((bytesCopied * 100 / streamSize).toInt(), bytes.toLong(), speed))
bytes = read(buffer) bytes = read(buffer)
} }
timer.cancel() timer.cancel()
}.flowOn(Dispatchers.IO).distinctUntilChangedBy { it.progress } }.flowOn(Dispatchers.IO)
} }

View File

@@ -42,7 +42,6 @@ import dagger.assisted.AssistedInject
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
@@ -264,7 +263,7 @@ class DownloadWorker @AssistedInject constructor(
connection.inputStream.use { input -> connection.inputStream.use { input ->
FileOutputStream(request.file, !isNewFile).use { FileOutputStream(request.file, !isNewFile).use {
input.copyTo(it, request.size).collectLatest { p -> onProgress(p) } input.copyTo(it, request.size).collect { p -> onProgress(p) }
} }
} }
@@ -281,17 +280,15 @@ class DownloadWorker @AssistedInject constructor(
private suspend fun onProgress(downloadInfo: DownloadInfo) { private suspend fun onProgress(downloadInfo: DownloadInfo) {
if (!isStopped && !download.isFinished) { if (!isStopped && !download.isFinished) {
val progress = ((downloadedBytes + downloadInfo.bytesCopied) * 100 / totalBytes).toInt() downloadedBytes += downloadInfo.bytesCopied
val bytesRemaining = totalBytes - (downloadedBytes + downloadInfo.bytesCopied)
val progress = (downloadedBytes * 100 / totalBytes).toInt()
val bytesRemaining = totalBytes - downloadedBytes
val speed = if (downloadInfo.speed == 0L) 1 else downloadInfo.speed val speed = if (downloadInfo.speed == 0L) 1 else downloadInfo.speed
// Individual file progress can be negligible in contrast to total progress // Individual file progress can be negligible in contrast to total progress
// Only notify the UI if progress is greater or speed has changed to avoid being rate-limited by Android // Only notify the UI if progress is greater or speed has changed to avoid being rate-limited by Android
if (progress > totalProgress || speed != download.speed) { if (progress > totalProgress || speed != download.speed) {
if (downloadInfo.progress == 100) {
downloadedBytes += downloadInfo.bytesCopied
}
download.apply { download.apply {
this.progress = progress this.progress = progress
this.speed = downloadInfo.speed this.speed = downloadInfo.speed