2

I know the Column(){...} will be recomposition when either b1 or b2 is changed.

If I hope that Column(){...} can be re-composed only when b2 is changed and Column(){...} doesn't be recomposed when b1 is changed, how can I do?

@Composable fun ScreenDetail( mViewMode: SoundViewModel ) { val b1=mViewMode.a1.collectAsState(initial = 0) val b2=mViewMode.a2.collectAsState(initial = 0) Column() { Text(" ${b1.value} ${b2.value}") Text(Calendar.getInstance().time.toSeconds()) } } fun Date.toSeconds():String{ return SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.US).format(this) } class SoundViewModel(): ViewModel() { var i = 0 val a1: Flow<Int> = flow { while (true) { emit(i++) delay(1000) } } val a2: Flow<Int> = flow { while (true) { emit(i) delay(2000) } } } 

1 Answer 1

7

You need to create scopes if you need to have scoped recompositions. By scopes i mean creating a Composable that is not inline unlike Column, Row or Box. You can check answer and articles in this link.

Compose recomposes closest scope/function that States are read. If you read

 Text(" ${b1.value} ${b2.value}") 

your Column will be recomposed when any of these states changes. But as mentioned above even if you read any of the they should have changed because Column doesn't create a scope

@Composable fun ScreenDetail2( mViewMode: SoundViewModel ) { val b1=mViewMode.a1.collectAsState(initial = 0) val b2=mViewMode.a2.collectAsState(initial = 0) Column(modifier= Modifier.background(getRandomColor()).fillMaxWidth()) { Text("${b1.value}") } Column(modifier= Modifier.background(getRandomColor()).fillMaxWidth()) { Text("${b2.value}") } } 

But if you create a function such as

@Composable private fun MyColumn(counter:Int){ Column(modifier= Modifier.background(getRandomColor()).fillMaxWidth()) { Text("$counter") } } 

you will be having scopes for each value you read

@Composable fun ScreenDetail3( mViewMode: SoundViewModel ) { val b1=mViewMode.a1.collectAsState(initial = 0) val b2=mViewMode.a2.collectAsState(initial = 0) MyColumn(b1.value) MyColumn(b2.value) } 

As you can see in the gif ScreenDetail2 recomposes each Column when b1 or b2 changes but ScreenDetail3 only recomposes respective scope of function. I changed delay time of b1 to 300 and b2 to 2000 to make recomposition easy to observe visually.

2 tolumns on top is from ScreenDetail2, and the bottom is from ScreenDetail3

enter image description here

Recomposition can be observer in many ways, i add 2

class Ref(var value: Int)

// Note the inline function below which ensures that this function is essentially // copied at the call site to ensure that its logging only recompositions from the // original call site. @Composable inline fun LogCompositions(msg: String) { val ref = remember { Ref(0) } SideEffect { ref.value++ } println("$msg, recomposition: ${ref.value}") } 

or changing colors

fun getRandomColor() = Color( red = Random.nextInt(256), green = Random.nextInt(256), blue = Random.nextInt(256), alpha = 255 ) 
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks! Can I always get the same result when I use ScreenDetail3, I think Android Studio optimize recomposition to effect this result.
And more, I can't find You need to create scopes if you need to have scoped recompositions. in official document.
When you create scopes you definitely get the same results. I suggest you to check this article, and the answer i posted, and this one. And, yes, it's not mentioned in official documents. You can observer recomposition with AS dolphin layout and i'm adding my answer two functions to observe visually or in the logs.
Thanks! I updated my code based your thinking at the question stackoverflow.com/questions/72696157/… I'm still confused when Jetpack Compose will launch recomposition and what will be recomposition?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.