https://kotlinlang.org logo
#compose
Title
# compose
d

Diego Marulanda

06/10/2020, 8:12 PM
hi, i have next code:
Copy code
@Composable
fun Residencelist(){
    coreApiService.get("${BASE_URL}list/") { response: String ->
        val response = Gson().fromJson(response, ResponseResidences::class.java)
        MaterialTheme {
            Column(Modifier.padding(bottom = 1.dp).fillMaxWidth()) {
                VerticalScroller() {
                    Column(Modifier.padding(3.dp).fillMaxWidth()) {
                        response.residences!!.forEach {
                            if (it != null) {
                                newCarrouselCard(it.name!!,
                                    it.mainImage!!,
                                    it.additionalInformation!!.images,
                                    it.residenceDescription!!,
                                    "${it.price} ${it.currency}")
                                    Divider(height = 10.dp)
                            } else newCard("Residences not found")
                        }
                    }
                }
            }
        }
    }
}
and when I try to compile, get this error:
Functions which invoke @Composable functions must be marked with the @Composable annotation
in the
val
line, but I don't understand why? because I call other normal functions from Glide library and it works,
a

Adam Powell

06/10/2020, 8:15 PM
You're trying to call composable functions from the response callback of your http request
d

Diego Marulanda

06/10/2020, 8:17 PM
omg... i'm so stupid...🙃🙃
a

Adam Powell

06/10/2020, 8:18 PM
I would probably convert this in two stages, first write a
suspend
version of your API service request, (or if you're using retrofit, use the suspend variant it can give you) then use this pattern:
Copy code
var response by state<ResponseResidences?> { null }
launchInComposition(url) {
    response = suspendingGet(url)
}

if (response == null) {
    // return, or show a loading state
    return
}

MaterialTheme {
    // the rest of your UI
d

Diego Marulanda

06/10/2020, 8:19 PM
thanks a lot
j

jw

06/10/2020, 8:19 PM
And it will also mean you're not creating a new
Gson
instance for every call which is very bad.
a

Adam Powell

06/10/2020, 8:19 PM
yeah probably don't do that too, try to bring that dependency out to another scope 🙂
if you pass your request information like the url to
launchInComposition(...)
then it will cancel and re-launch if the request information changes
z

zhuinden

06/27/2020, 12:10 PM
is it possible to make a
@Composable
function suspending? 🤔
a

Adam Powell

06/27/2020, 2:09 PM
in theory, yes, folks have brought up potential parallels to things like react suspense and the like that might end up being useful. In practice it would probably work differently enough from both regular suspend and composable functions that it could significantly complicate the mental model of both, so it's not likely something we would explore in earnest until after 1.0.
Composable functions are meant to be declarative and have no concept of time; they work in snapshots. Something changing means the whole scope is invalidated and rerun, with skipping logic avoiding repeat work for nested calls. Adding a concept of time in the form of suspend makes that potentially a lot harder to teach, potentially different rules about which part of a suspend composable restarts, resumes, or skips and why, and I'm not sure that it enables better enough patterns over launching a suspending state producer like the above to be worth the tradeoffs
We have been talking a lot over the last week or two about which higher-level constructs like that to offer in the base API though, things that add some syntactic sugar to the above and parallel
CoroutineScope.produce
as hot state updaters