```@Composable fun startScreen() { FlowComponen...
# compose
m
Copy code
@Composable
fun startScreen() {
   FlowComponent(sflow = myfirstFlow())
}

@Composable
fun FlowComponent(sflow: Flow<String>){
       val cnt:String by sflow.collectAsState("")
       val sl =state { mutableListOf<String>()}
       sl.value.add(cnt)
       Box(Modifier.preferredHeight(150.dp)){
          sl.value.forEach {
            Text(it)
        }
    }
}

fun myfirstFlow()=flow<String>{
    val t=110L
   emit("task 1 succeded")
    delay(t)
   emit("task 2 failed")
    delay(t)
    emit("task 3 succeded")
    delay(t)
    emit("task 4 failed")
    delay(t)
    //emit("uuu"+getNewsPapers(null))
This is a startup screen as I run several functions I intend to emit a string to the flow component that will add it to a list of stings and then write them on screen. And it works but only if I add a certain delay between emits, if the delay is to small or null then I only get the first and last emit. I I'm wrong if i believe that this should work without any delay at all?
z
From what you’ve described, your strings are more like “events” than “state”, so
collectAsState
is probably not what you want. For things that are like “state”, it’s typical to conflate values that are emitted one after the other, since any work to be done to render a previous state will be undone or redone to render the subsequent state anyway. The “state” here is the actual list of strings. There are a couple ways you could refactor this:
Copy code
@Composable
fun FlowComponent(stringFlow: Flow<String>) {
  val stringListFlow: Flow<List<String>> = remember(stringFlow) {
    stringFlow.scan(emptyList()) { strings, s -> strings + s }
  }
  val stringList: List<String> by stringListFlow.collectAsState(emptyList())
  …
Or
Copy code
@Composable
fun FlowComponent(stringFlow: Flow<String>) {
  var stringList: MutableList<String> by remember { mutableStateOf(emptyList<String>()) }
  launchInComposition {
    stringFlow.collect { stringList += it }
  }
m
Great many thanks! First works perfectly, second doesn't compile Type 'TypeVariable(T)' has no method 'getValue(Nothing?, KProperty<*>)' and thus it cannot serve as a delegate. In the remember{ mutableListOf<String>()}
z
Yea, it was wrong. Updated the snippet.
m
Concerning your remark about "events" and "state" I totally agree, I meant to use sflow.collect but was not possible and just I found collectAsState, and to finish with I was totally unaware of scan ..... all and all a little better documentation would be grate but it's ok . I'm working on this https://drive.google.com/file/d/1p647P0bOjpoqZtDZQEwu-9bIZmyleibn/view?usp=sharing It's a tool for language students, you don't have to look at it just in case. Any way many thanks
👍 1
c
In general, any code that modifies the data that is read during composition should be viewed with suspicion. It is not always bad but it is often difficult to get right. Compose works best if the data can be rendered without manipulation. Stateless filters, maps, etc are fine but mutation is not. Use of
scan
above works better for compose because the mutation is done outside of composition and then is presented to compose as an immutable list.
m
Well how then I'm supposed to build something like the android logcat? I thoug that emit was a sound option .... and unfortunately I don't see many more...
z
Which
emit
are you referring to? Compose’s
emit
has nothing to do with this really. Also note that “during composition” means done directly inside a Composable function, which is only invoked during an actual composition pass.
launchInComposition
(and
collectAsState
, which uses
launchInComposition
under the hood) launch coroutines that run outside of composition.
I think @Chuck Jazdzewski [G] is referring to
sl.value.add(cnt)
in your initial code snippet.
c
Yes. Sorry that wasn't more clear.
m
You are both totally right, I found myself at odds with the s1.value.add(cnt), but in my opinion is worth considering how much knowledge is necessary for doing a simple thing, because at the end one way or another you are just adding strings to a list to be printed ....
z
At a higher level, I would probably argue that this sort of accumulation logic should not live in the view layer (i.e. compose) at all, but in a
ViewModel
or some other non-view-related code. That type would then expose the current UI state via something like a
StateFlow<List<String>>
.
💯 1