Skip to content

Commit

Permalink
Stop returning to composition to callback
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Banes committed Jun 18, 2020
1 parent 29ff6c4 commit 63063a2
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 47 deletions.
76 changes: 34 additions & 42 deletions coil/src/main/java/dev/chrisbanes/accompanist/coil/Coil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import android.graphics.drawable.Drawable
import androidx.compose.Composable
import androidx.compose.getValue
import androidx.compose.launchInComposition
import androidx.compose.onCommit
import androidx.compose.onDispose
import androidx.compose.mutableStateOf
import androidx.compose.remember
import androidx.compose.setValue
import androidx.compose.state
Expand Down Expand Up @@ -93,7 +92,7 @@ fun CoilImage(
}

/**
* Creates a composable that will attempt to load the given [data] using [Coil], and then
* Creates a composable that will attempt to load the given [request] using [Coil], and then
* display the result in an [Image].
*
* @param request The request to execute. If the request does not have a [GetRequest.sizeResolver]
Expand Down Expand Up @@ -124,24 +123,21 @@ fun CoilImage(
onRequestCompleted: (RequestResult) -> Unit = emptySuccessLambda
) {
var result by state<RequestResult?> { null }
val callback = mutableStateOf(onRequestCompleted)

val requestActor = remember(request) {
CoilRequestActor(request) { result = it }
}
val requestActor = remember(request) { CoilRequestActor(request) }

launchInComposition(requestActor) {
// Launch the Actor
requestActor.run()
}

onDispose {
// When we leave the composition, close the Actor channel
requestActor.close()
}
requestActor.run { actorResult ->
// Store the result
result = actorResult

onCommit(result) {
// Execute the onRequestCompleted callback if we have a new result
result?.also { onRequestCompleted(it) }
if (actorResult != null) {
// Execute the onRequestCompleted callback if we have a new result
callback.value(actorResult)
}
}
}

val painter = when (val r = result) {
Expand Down Expand Up @@ -188,30 +184,30 @@ fun CoilImage(
}

private fun CoilRequestActor(
request: GetRequest,
onResult: (RequestResult?) -> Unit
) = RequestActor<IntPxSize, RequestResult?>(
execute = { size ->
val requestWidth = size.width.value
val requestHeight = size.height.value
when {
request.sizeResolver != null -> {
// If the request has a sizeResolver set, we just execute the request as-is
request.execute()
}
requestWidth > 0 && requestHeight > 0 -> {
// If we have a non-zero size, we can modify the request to include the size
request.newBuilder()
.size(requestWidth, requestHeight)
.build()
.execute()
}
request: GetRequest
) = RequestActor<IntPxSize, RequestResult?> { size ->
when {
request.sizeResolver != null -> {
// If the request has a sizeResolver set, we just execute the request as-is
request
}
size != IntPxSize.Zero -> {
// If we have a non-zero size, we can modify the request to include the size
request.newBuilder()
.size(size.width.value, size.height.value)
.build()
}
else -> {
// Otherwise we have a zero size, so no point executing a request
else -> null
null
}
},
onResult = onResult
)
}?.let { transformedRequest ->
// Now execute the request in Coil...
Coil.imageLoader(transformedRequest.context)
.execute(transformedRequest)
.toResult()
}
}

/**
* Represents the result of an image request.
Expand Down Expand Up @@ -259,10 +255,6 @@ private fun coil.request.RequestResult.toResult(): RequestResult {
}
}

private suspend fun GetRequest.execute(): RequestResult {
return Coil.imageLoader(context).execute(this).let { it.toResult() }
}

@Composable
internal fun defaultFailurePainterGetter(error: ErrorResult): Painter? {
return error.image?.let { image ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,16 @@ package dev.chrisbanes.accompanist.coil

import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.consumeAsFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.receiveAsFlow

internal class RequestActor<Param, Result>(
private val execute: suspend (Param) -> Result,
private val onResult: (Result) -> Unit
private val execute: suspend (Param) -> Result
) {
private val channel = Channel<Param>(Channel.CONFLATED)

suspend fun run() {
channel.consumeAsFlow()
suspend fun run(onResult: (Result) -> Unit) {
channel.receiveAsFlow()
.distinctUntilChanged()
.collect { param -> onResult(execute(param)) }
}
Expand Down

0 comments on commit 63063a2

Please sign in to comment.