HelloCW
HelloCW

Reputation: 2325

When will Jetpack Compose launch recomposition and what will be recomposition?

I was told "You need to create scopes if you need to have scoped recompositions" by Thracian in the question.

It seems that I can't find the policy from official documnet.

The Code A is based the answer of Thracian. I get Result A when I run Code A.

1: When will MyColumn(Calendar.getInstance().time.toSeconds()) be launched ?

2: Why is CallMyColumn() launched only one time?

Code A

class SoundViewModel(): ViewModel() {
    var i = 0
    val a1: Flow<Int> = flow {
        while (true) {
            emit(i++)
            delay(500)
        }
    }

    val a2: Flow<Int> = flow {
        while (true) {
            emit(i)
            delay(2000)
        }
    }
}

@Composable
fun ScreenDetail(   
    mViewMode: SoundViewModel   
) {
    Column() {
        val b1=mViewMode.a1.collectAsState(initial = 0)
        val b2=mViewMode.a2.collectAsState(initial = 0)

        MyColumn("A: "+ b1.value.toString())
        MyColumn("B: "+ b2.value.toString())
        MyColumn("C: "+ "Hello")                          //It's only fired one time
        Log.e("My","D: World")
        MyColumn(Calendar.getInstance().time.toSeconds()) //I don't know when it is fired
        CallMyColumn()                                    //It's only fired one time
    }
}

@Composable
private fun MyColumn(counter:String){
    Column(modifier= Modifier.background(color =getRandomColor()).fillMaxWidth()) {
        Text(counter)
        Log.e("My",counter)
    }
}

@Composable
private fun CallMyColumn() {
     MyColumn("Call "+ Calendar.getInstance().time.toSeconds())
//    Column(modifier = Modifier.background(color = getRandomColor()).fillMaxWidth()) {
//        val s = "Call " + Calendar.getInstance().time.toSeconds()
//        Text(s)
//        Log.e("My", s)
//    }
}

fun getRandomColor() =  Color(
    red = Random.nextInt(256),
    green = Random.nextInt(256),
    blue = Random.nextInt(256),
    alpha = 255
)

fun Date.toSeconds():String{
    return SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.US).format(this)
}

Result A

2022-06-21 12:02:34.761 19237-19237/info.dodata.soundmeter E/My: A: 0
2022-06-21 12:02:34.761 19237-19237/info.dodata.soundmeter E/My: B: 0
2022-06-21 12:02:34.762 19237-19237/info.dodata.soundmeter E/My: C: Hello
2022-06-21 12:02:34.762 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:34.764 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:34
2022-06-21 12:02:34.765 19237-19237/info.dodata.soundmeter E/My: Call 2022/06/21 04:02:34
2022-06-21 12:02:34.849 19237-19237/info.dodata.soundmeter E/My: B: 1
2022-06-21 12:02:34.849 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:35.230 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:35.231 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:35
2022-06-21 12:02:35.365 19237-19237/info.dodata.soundmeter E/My: A: 1
2022-06-21 12:02:35.366 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:35.869 19237-19237/info.dodata.soundmeter E/My: A: 2
2022-06-21 12:02:35.870 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:36.365 19237-19237/info.dodata.soundmeter E/My: A: 3
2022-06-21 12:02:36.365 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:36.367 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:36
2022-06-21 12:02:36.871 19237-19237/info.dodata.soundmeter E/My: A: 4
2022-06-21 12:02:36.873 19237-19237/info.dodata.soundmeter E/My: B: 4
2022-06-21 12:02:36.873 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:37.368 19237-19237/info.dodata.soundmeter E/My: A: 5
2022-06-21 12:02:37.368 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:37.369 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:37
2022-06-21 12:02:37.872 19237-19237/info.dodata.soundmeter E/My: A: 6
2022-06-21 12:02:37.873 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:38.371 19237-19237/info.dodata.soundmeter E/My: A: 7
2022-06-21 12:02:38.371 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:38.373 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:38
2022-06-21 12:02:38.873 19237-19237/info.dodata.soundmeter E/My: A: 8
2022-06-21 12:02:38.873 19237-19237/info.dodata.soundmeter E/My: B: 8
2022-06-21 12:02:38.873 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:39.375 19237-19237/info.dodata.soundmeter E/My: A: 9
2022-06-21 12:02:39.375 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:39.377 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:39
2022-06-21 12:02:39.875 19237-19237/info.dodata.soundmeter E/My: A: 10
2022-06-21 12:02:39.875 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:40.375 19237-19237/info.dodata.soundmeter E/My: A: 11
2022-06-21 12:02:40.375 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:40.377 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:40
2022-06-21 12:02:40.861 19237-19237/info.dodata.soundmeter E/My: B: 12
2022-06-21 12:02:40.861 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:40.882 19237-19237/info.dodata.soundmeter E/My: A: 12
2022-06-21 12:02:40.882 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:41.401 19237-19237/info.dodata.soundmeter E/My: A: 13
2022-06-21 12:02:41.402 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:41.405 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:41
2022-06-21 12:02:41.898 19237-19237/info.dodata.soundmeter E/My: A: 14
2022-06-21 12:02:41.898 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:42.404 19237-19237/info.dodata.soundmeter E/My: A: 15
2022-06-21 12:02:42.404 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:42.408 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:42
2022-06-21 12:02:42.869 19237-19237/info.dodata.soundmeter E/My: B: 16
2022-06-21 12:02:42.869 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:42.895 19237-19237/info.dodata.soundmeter E/My: A: 16
2022-06-21 12:02:42.895 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:43.401 19237-19237/info.dodata.soundmeter E/My: A: 17
2022-06-21 12:02:43.401 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:43.402 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:43
2022-06-21 12:02:43.908 19237-19237/info.dodata.soundmeter E/My: A: 18
2022-06-21 12:02:43.908 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:44.426 19237-19237/info.dodata.soundmeter E/My: A: 19
2022-06-21 12:02:44.426 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:44.431 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:44
2022-06-21 12:02:44.873 19237-19237/info.dodata.soundmeter E/My: B: 20
2022-06-21 12:02:44.874 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:44.925 19237-19237/info.dodata.soundmeter E/My: A: 20
2022-06-21 12:02:44.925 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:45.426 19237-19237/info.dodata.soundmeter E/My: A: 21
2022-06-21 12:02:45.427 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:45.428 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:45
2022-06-21 12:02:45.927 19237-19237/info.dodata.soundmeter E/My: A: 22
2022-06-21 12:02:45.927 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:46.429 19237-19237/info.dodata.soundmeter E/My: A: 23
2022-06-21 12:02:46.429 19237-19237/info.dodata.soundmeter E/My: D: World
2022-06-21 12:02:46.430 19237-19237/info.dodata.soundmeter E/My: 2022/06/21 04:02:46
2022-06-21 12:02:46.878 19237-19237/info.dodata.soundmeter E/My: B: 24
2022-06-21 12:02:46.878 19237-19237/info.dodata.soundmeter E/My: D: World

Added Content:

To Thracian: Thanks!

I run Code B and get Result B.

I don't know why Log.e("My","Canvas "+ Calendar.getInstance().time.toSeconds()) can be launched repeated, could you tell me ?

Code B

//The other codes are same as Code A.

@Composable
private fun CallMyColumn() {
    MyColumn("Call "+ Calendar.getInstance().time.toSeconds())

    Canvas(
        modifier = Modifier
            .fillMaxSize()
            .padding(10.dp)
    ) {
        Log.e("My","Canvas "+ Calendar.getInstance().time.toSeconds())
    }
}

Result B

2022-06-21 17:38:53.026 11931-11931/info.dodata.soundmeter E/My: A: 0
2022-06-21 17:38:53.027 11931-11931/info.dodata.soundmeter E/My: B: 0
2022-06-21 17:38:53.028 11931-11931/info.dodata.soundmeter E/My: C: Hello
2022-06-21 17:38:53.028 11931-11931/info.dodata.soundmeter E/My: D: World
2022-06-21 17:38:53.030 11931-11931/info.dodata.soundmeter E/My: 2022/06/21 09:38:53
2022-06-21 17:38:53.032 11931-11931/info.dodata.soundmeter E/My: Call 2022/06/21 09:38:53
2022-06-21 17:38:53.594 11931-11931/info.dodata.soundmeter E/My: Canvas 2022/06/21 09:38:53
2022-06-21 17:38:54.171 11931-11931/info.dodata.soundmeter E/My: B: 1
2022-06-21 17:38:54.171 11931-11931/info.dodata.soundmeter E/My: D: World
2022-06-21 17:38:54.181 11931-11931/info.dodata.soundmeter E/My: 2022/06/21 09:38:54
2022-06-21 17:38:54.239 11931-11931/info.dodata.soundmeter E/My: Canvas 2022/06/21 09:38:54
2022-06-21 17:38:54.585 11931-11931/info.dodata.soundmeter E/My: A: 1
2022-06-21 17:38:54.585 11931-11931/info.dodata.soundmeter E/My: D: World
2022-06-21 17:38:54.593 11931-11931/info.dodata.soundmeter E/My: Canvas 2022/06/21 09:38:54
2022-06-21 17:38:55.175 11931-11931/info.dodata.soundmeter E/My: A: 2
2022-06-21 17:38:55.175 11931-11931/info.dodata.soundmeter E/My: D: World
2022-06-21 17:38:55.176 11931-11931/info.dodata.soundmeter E/My: 2022/06/21 09:38:55
2022-06-21 17:38:55.184 11931-11931/info.dodata.soundmeter E/My: Canvas 2022/06/21 09:38:55
2022-06-21 17:38:55.423 11931-11931/info.dodata.soundmeter E/My: Canvas 2022/06/21 09:38:55
2022-06-21 17:38:55.683 11931-11931/info.dodata.soundmeter E/My: A: 3
2022-06-21 17:38:55.684 11931-11931/info.dodata.soundmeter E/My: D: World
2022-06-21 17:38:55.711 11931-11931/info.dodata.soundmeter E/My: Canvas 2022/06/21 09:38:55
2022-06-21 17:38:56.100 11931-11931/info.dodata.soundmeter E/My: B: 4
2022-06-21 17:38:56.100 11931-11931/info.dodata.soundmeter E/My: D: World
2022-06-21 17:38:56.104 11931-11931/info.dodata.soundmeter E/My: 2022/06/21 09:38:56
2022-06-21 17:38:56.122 11931-11931/info.dodata.soundmeter E/My: Canvas 2022/06/21 09:38:56
2022-06-21 17:38:56.183 11931-11931/info.dodata.soundmeter E/My: A: 4
2022-06-21 17:38:56.183 11931-11931/info.dodata.soundmeter E/My: D: World
2022-06-21 17:38:56.190 11931-11931/info.dodata.soundmeter E/My: Canvas 2022/06/21 09:38:56
2022-06-21 17:38:56.692 11931-11931/info.dodata.soundmeter E/My: A: 5
2022-06-21 17:38:56.692 11931-11931/info.dodata.soundmeter E/My: D: World
2022-06-21 17:38:56.712 11931-11931/info.dodata.soundmeter E/My: Canvas 2022/06/21 09:38:56
2022-06-21 17:38:57.195 11931-11931/info.dodata.soundmeter E/My: A: 6
2022-06-21 17:38:57.195 11931-11931/info.dodata.soundmeter E/My: D: World
2022-06-21 17:38:57.197 11931-11931/info.dodata.soundmeter E/My: 2022/06/21 09:38:57
2022-06-21 17:38:57.207 11931-11931/info.dodata.soundmeter E/My: Canvas 2022/06/21 09:38:57
2022-06-21 17:38:57.695 11931-11931/info.dodata.soundmeter E/My: A: 7
2022-06-21 17:38:57.695 11931-11931/info.dodata.soundmeter E/My: D: World
2022-06-21 17:38:57.704 11931-11931/info.dodata.soundmeter E/My: Canvas 2022/06/21 09:38:57
2022-06-21 17:38:58.118 11931-11931/info.dodata.soundmeter E/My: B: 8
2022-06-21 17:38:58.119 11931-11931/info.dodata.soundmeter E/My: D: World
2022-06-21 17:38:58.122 11931-11931/info.dodata.soundmeter E/My: 2022/06/21 09:38:58

Upvotes: 0

Views: 708

Answers (1)

Thracian
Thracian

Reputation: 67293

When a State is read it triggers recomposition in nearest scope. And a scope is a function that is not marked with inline and returns Unit. Column, Row and Box are inline functions and because of that they don't create scopes.

Sources

https://dev.to/zachklipp/scoped-recomposition-jetpack-compose-what-happens-when-state-changes-l78

https://www.jetpackcompose.app/articles/donut-hole-skipping-in-jetpack-compose

https://twitter.com/intelligibabble/status/1435676765725224964?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1435676765725224964%7Ctwgr%5E%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fwww.jetpackcompose.app%2Farticles%2Fdonut-hole-skipping-in-jetpack-compose

Jetpack Compose Smart Recomposition

Why does mutableStateOf without remember work sometimes?

Same goes for Modifiers too. When they read states without lambda they are recomposed too.

For instance Modifier.offset() is recomposed when the state it reads changes however Modifier.offset{} calls Layout and Draw phases. When you chain Modifiers they create a CombinedModifier and any Modifier chained that reads a State in Composition phase causes that subsection of CombinedModifier to change and recomposition happens in your Composable with the updated Modifier.

https://developer.android.com/jetpack/compose/performance

Also i have tutorial that covers recomposition, smart recomposition, modifier recomposition and phases. You can check it out and play with it too, and see effects. State section covers these topics.

https://github.com/SmartToolFactory/Jetpack-Compose-Tutorials

Upvotes: 0

Related Questions