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)
        }
    }
}
z.g.y
  • 5,512
  • 4
  • 10
  • 36
HelloCW
  • 843
  • 22
  • 125
  • 310

1 Answers1

6

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
)
Thracian
  • 43,021
  • 16
  • 133
  • 222
  • Thanks! Can I always get the same result when I use `ScreenDetail3`, I think Android Studio optimize recomposition to effect this result. – HelloCW Jun 19 '22 at 11:29
  • And more, I can't find `You need to create scopes if you need to have scoped recompositions. ` in official document. – HelloCW Jun 19 '22 at 11:31
  • When you create scopes you definitely get the same results. I suggest you to check this [article](https://www.jetpackcompose.app/articles/donut-hole-skipping-in-jetpack-compose), and the answer i posted, and [this one](https://stackoverflow.com/a/71047185/5457853). 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. – Thracian Jun 19 '22 at 11:48
  • Thanks! I updated my code based your thinking at the question https://stackoverflow.com/questions/72696157/when-will-jetpack-compose-launch-recomposition-and-what-will-be-recomposition I'm still confused when Jetpack Compose will launch recomposition and what will be recomposition? – HelloCW Jun 21 '22 at 06:41