Reputation: 85
I'm uploading files with retrofit. I want to listen to the retrofit progress in Kotlin and show it with the progress bar on ui. When I did research on this, I found a good example of this in java using PublishSubject on this page. Is it possible to show progress bar when upload image via Retrofit 2? I want to adapt this to my own code, but I can't decide whether I should use Flow or Channel instead of PublishSubject in Kotlin.
My requestbody class with broadcastChannel:
class ProgressRequestBody : RequestBody {
val mFile: File
val ignoreFirstNumberOfWriteToCalls : Int
constructor(mFile: File) : super(){
this.mFile = mFile
ignoreFirstNumberOfWriteToCalls = 0
}
constructor(mFile: File, ignoreFirstNumberOfWriteToCalls : Int) : super(){
this.mFile = mFile
this.ignoreFirstNumberOfWriteToCalls = ignoreFirstNumberOfWriteToCalls
}
var numWriteToCalls = 0
val getProgress = BroadcastChannel<Float>(1)
override fun contentType(): MediaType? {
return "image/*".toMediaTypeOrNull()
}
@Throws(IOException::class)
override fun contentLength(): Long {
return mFile.length()
}
@Throws(IOException::class)
override fun writeTo(sink: BufferedSink) {
numWriteToCalls++
val fileLength = mFile.length()
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
val `in` = FileInputStream(mFile)
var uploaded: Long = 0
try {
var read: Int
var lastProgressPercentUpdate = 0.0f
read = `in`.read(buffer)
while (read != -1) {
uploaded += read.toLong()
sink.write(buffer, 0, read)
read = `in`.read(buffer)
// when using HttpLoggingInterceptor it calls writeTo and passes data into a local buffer just for logging purposes.
// the second call to write to is the progress we actually want to track
if (numWriteToCalls > ignoreFirstNumberOfWriteToCalls ) {
val progress = (uploaded.toFloat() / fileLength.toFloat()) * 100f
//prevent publishing too many updates, which slows upload, by checking if the upload has progressed by at least 1 percent
if (progress - lastProgressPercentUpdate > 1 || progress == 100f) {
// publish progress
getProgress.send(progress)
lastProgressPercentUpdate = progress
}
}
}
} finally {
`in`.close()
}
}
companion object {
private val DEFAULT_BUFFER_SIZE = 2048
}
}
The problem is that broadcastChannel.send(progress)
wants the function to suspend but the RequestBody writeTo
method should not suspend. In this case, I am confused. Should I use Flow or BroadCastChannel? Can you help me?
Upvotes: 3
Views: 1778
Reputation: 53
You should use MutableStateFlow:
val getProgress = MutableStateFlow<Float>(0f) // Initial value is 0
Then:
getProgress.value = progress
See more: StateFlow and SharedFlow
Upvotes: 3
Reputation: 2719
val getProgress = MutableSharedFlow<Float>(extraBufferCapacity = 1)
getProgress.tryEmit(progress)
Upvotes: 1