kotlin - PublishSubject 与 Kotlin 协程(流/ channel )

标签 kotlin retrofit2 kotlin-coroutines

我正在上传带有改造的文件。想在Kotlin中听听retrofit进度,在ui上用进度条显示。当我对此进行研究时,我在此页面上使用 PublishSubject 在 java 中找到了一个很好的例子。 Is it possible to show progress bar when upload image via Retrofit 2? 我想使它适应我自己的代码,但我无法决定在 Kotlin 中我应该使用 Flow 还是 Channel 而不是 PublishSubject。

我的带有 broadcastChannel 的 requestbody 类:

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

问题是 broadcastChannel.send(progress) 希望函数暂停,但 RequestBody writeTo 方法不应该暂停。在这种情况下,我很困惑。我应该使用 Flow 还是 BroadCastChannel?你能帮帮我吗?

最佳答案

你应该使用 MutableStateFlow:

val getProgress = MutableStateFlow<Float>(0f) // Initial value is 0

然后:

getProgress.value = progress

查看更多:StateFlow and SharedFlow

关于kotlin - PublishSubject 与 Kotlin 协程(流/ channel ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66736497/

相关文章:

generics - 使用Any时模棱两可的重载方法引用

android - 如何通过将其他对象字段保存为索引来按对象字段对 MutableMap 进行排序?

android - illegalstateexception 应为 BEGIN_OBJECT 但在第 1 行第 1 列路径 $ 处为 STRING

java - 改造迁移至2.0

kotlin - InternalCoroutinesApi注解是什么意思

kotlin - 内部类中的嵌套类

kotlin - 如何将 Kotlin lambda 转换为 String 然后再转换回 lambda?

java - 使用 XML 进行改造 - 元素在类中没有匹配项

android - 将 viewModelScope 与 LiveData 一起使用时出现问题

android - 带 fragment 的协程作用域