Anton Afanasev
08/23/2021, 12:28 PMonUpload
API on KMM platform. Android works fine, but iOS produce an InvalidMutabilityException
.I am looking for any feedback from the community. I am using ktor = 1.6.0
suspend fun uploadFile(
url: String,
byteArray: ByteArray,
progressCallback: (Float) -> Unit
) {
client.put<Unit>(url) {
onUpload { bytesSendTotal: Long, contentLength: Long ->
progressCallback((bytesSendTotal / contentLength.toFloat()) * 100)
}
body = byteArray
}
}
I call it from another class that is responsible for managing states of the uploaded object.
Dispatcher:
private val uploadDispatcher = CoroutineScope(Dispatchers.Main + SupervisorJob())
Call to the function:
uploadDispatcher.launch { api.uploadFile(url, byteArray) { progress ->
data = data.copy(state = Uploading(progress))
.also(onUploadProgress)
}
}
where the onUploadProgress
is lambda:
private val onUploadProgress: (Data) -> Unit,
As mentioned above, while executing this code on iOS I am receiving an InvalidMutabilityException
Looking into Ktor, it looks like the
UploadProgressListenerAttributeKey
marked with @SharedImmutable
which makes it deeply frozen and freeze the objects it refers to.
Considering that when upload progress change I need to wrap and update state sof my internal objects - how should I do that using provided onUpload
API?Igor Maric
08/23/2021, 2:16 PMAleksei Tirman [JB]
08/23/2021, 2:36 PMdata = data.copy(state = Uploading(progress))
.also(onUploadProgress)
}
Anton Afanasev
08/23/2021, 2:42 PMdata
is actually a mutable map:
private val dataMap = mutableMapOf<String, Data>()
@Serializable
private class Data(
val state: Data.State = Data.State.Idle,
val id: String? = null,
val fileName: String,
var byteArray: ByteArray,
var job: Job? = null,
) {
@Serializable
sealed class State {
object Idle : State()
object Deleted : State()
object Detached : State()
object Presigning : State()
data class Uploading(val progress: Float) : State()
data class Uploaded(val downloadUrl: String) : State()
data class Sent(val downloadUrl: String) : State()
}
}
I am using Data
to report changes with this object. Potentially there are can be multiple data
objects handle in the same time.Anton Afanasev
08/23/2021, 2:44 PMprogress
is the outcome of progressCallback that is invoked every ktor.onUpdate() and simply convert the progress to percentage amountAleksei Tirman [JB]
08/23/2021, 2:51 PMInvalidMutabilityException
reproducible without using definitions for all those classes?Anton Afanasev
08/23/2021, 2:52 PMAnton Afanasev
08/24/2021, 5:04 PMUploadProgressListenerAttributeKey
and DownloadProgressListenerAttributeKey
in io.ktor.client.features
They annotated with @SharedImmutable. Wondering if it is necessary, as apparently this is the reason why my own listener and data structure that handle onUpload/onDownload become frozen as well. And since I am trying to mutate them I got an In InvalidMutabilityException
.
Thank you in advanceAleksei Tirman [JB]
08/25/2021, 8:54 AMonDownload
lambda if those objects were defined outside of it. I've created an issue KTOR-3068 to address this problem. Unfortunately, I don't know how to work around this issue.russhwolf
08/25/2021, 12:26 PMflag
atomicAnton Afanasev
08/25/2021, 1:01 PMonDownload
and onUpload
listeners.Anton Afanasev
08/27/2021, 1:10 PMrusshwolf
08/27/2021, 1:29 PM