Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Jetpack Compose A to Z (short)

Ji Sungbin
February 23, 2023

Jetpack Compose A to Z (short)

Jetpack Compose A to Z 네이버/화해 강연 자료 (40분)

Ji Sungbin

February 23, 2023
Tweet

More Decks by Ji Sungbin

Other Decks in Programming

Transcript

  1. /** * Composable য֢ప੉࣌਷ ஹನૉ ೣࣻীࢲ ೙ࣻ੸ਵ۽ ࢎਊغݴ ௼ѱ 3о૑੄

    ৉ೡਸ ыणפ׮. * * 1. ݵ١ࢿ੄ ࠁ੢ * 2. ਤ஖ ݫݽ੉ઁ੉࣌ ഝࢿച * 3. ؘ੉ఠ ઁҕ ژח ஹನ੷࠶ ߑ୹ */ @MustBeDocumented @Retention(AnnotationRetention.BINARY) @Target( AnnotationTarget.FUNCTION, AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY_GETTER ) annotation class Composable
  2. // э਷ input ਸ ߉਷ ஹನ੷࠶ਸ ݵ١ࢿ੄ ࠁ੢ਵ۽ ೦࢚ ੤प೯ਸ

    Ѥցګ׮. // ݵ١ࢿ: э਷ ো࢑੄ Ѿҗח ೦࢚ زੌೞ׮ח ࢿ૕ @Composable fun Idempotent() { // ݅ড UI јन੉ ೙ਃೞ׮ݶ... Text(text = "ࢿ࠼ے٘") // ੉ ஹನ੷࠶਷ ೠ ߣ݅ प೯ػ׮. Text(text = System.currentTimeMillis().toString()) // ੉ ஹನ੷࠶਷ ೦࢚ ੤प೯ػ׮. }
  3. // ஹನ੷࠶਷ ۠ఋ੐ীࢲ Ѿ੿ػ ਋ࢶࣽਤী ݏѱ ߽۳۽ प೯ؽਵ۽ ஹನ੷࠶੄ प೯

    ࣽࢲী ੄ઓೞח Ѥ ০૑ ঋ׮. // ٮۄࢲ ݵ١ࢿਸ ࠁ੢ೞח Ѫ੉ ઺ਃೞ׮. lateinit var text: String @Composable fun PureFunction() { LoadText() ShowText() } @Composable private fun LoadText() { text = "Bye, world!" Text(text = "Load Text...") } @Composable private fun ShowText() { Text(text = text) // text is not initialized properly оמࢿ ੓਺ }
  4. // ஹನ੷࠶ ೣࣻ੄ दӒפ୊৬ call-site, ӒܻҊ प೯ػ ࣽࢲܳ ӝળਵ۽ Ҋਬೠ

    key о ࢤࢿغҊ, // ஹನૉח ೧׼ key ܳ ӝળਵ۽ ݽٚ ؘ੉ఠܳ ੷੢ೞҊ ҙܻೠ׮. // э਷ key ܳ о૓ ஹನ੷࠶੉ э਷ input ਵ۽ ੤प೯ ػ׮ݶ ӝઓী प೯ػ Ѿҗܳ Ӓ؀۽ ੤ࢎਊೠ׮. // -> ݵ١ࢿҗ ਤ஖ ݫݽ੉ઁ੉࣌੄ Ѿҗ // ਤ஖ ݫݽ੉ઁ੉࣌: э਷ ਤ஖ীࢲ э਷ input ਵ۽ प೯غݶ ೦࢚ э਷ output ੉ աৢ Ѫ੉ۄҊ о੿ೞҊ, // чਸ நयೞҊ ੤ࢎਊ ೞח ӝࣿ @Composable fun PositionMemoization() { repeat(5) { Text(text = "Bye, world!") // э਷ call-site ੉૑݅, ஹನ੷࠶ ؘ੉ఠо ׮ ׮ܲ ҕрী ੷੢ؽ } }
  5. /** * @Composable (input) -> output * ੉ ೣࣻ੄ ҃਋

    input ਷ ܻࣗझ ই੉٣, output ਷ ܻࣗझ чܳ աఋշפ׮. * * ੉ ೣࣻ੄ @Composable ਷ ؘ੉ఠܳ ઁҕೞח ৉ೡਸ ೤פ׮. */ @Composable fun stringResource(@StringRes id: Int): String { val resources = resources() return resources.getString(id) } /** * @Composable (input) -> Unit * ੉ ೣࣻ੄ ҃਋ input җ output ੉ হणפ׮. * * ੉ ೣࣻ੄ @Composable ਷ ஹನ੷࠶ਸ ߑ୹ೞח ৉ೡਸ ೤פ׮. */ @Composable fun ByeWorld() { Text(text = "Bye, world!") }
  6. /** * ஹನૉ੄ ݽٚ ؘ੉ఠܳ ੷੢ೞҊ ҙܻೞח ௿ېझ ੑפ׮. *

    Gap Buffer ੗ܐҳઑ৬ ےؒ ঘࣁझ۽ ҳഅعҊ, ղࠗ ؘ੉ఠח Array<Any?> ী ੷੢ؾפ׮. */ internal class SlotTable : CompositionData, Iterable<CompositionGroup>
  7. Gap Buffer: زੌೠ ਤ஖ Ӕ୊ী ௿۞झఠ݂ػ ബਯ੸ੋ ࢗੑ ߂ ࢏ઁ

    ੘সਸ ೲਊೞח ز੸ ߓৌ 1, ୡӝ Gap ࢤࢿ: O(N) [(v)_, _, _, _, _, _, _, _, _, _] // _ ח Gap, (v) ח അ੤ cursor ܳ աఋն
  8. Gap Buffer: زੌೠ ਤ஖ Ӕ୊ী ௿۞झఠ݂ػ ബਯ੸ੋ ࢗੑ ߂ ࢏ઁ

    ੘সਸ ೲਊೞח ز੸ ߓৌ 1, ୡӝ Gap ࢤࢿ: O(N) [(v)_, _, _, _, _, _, _, _, _, _] // _ ח Gap, (v) ח അ੤ cursor ܳ աఋն 2. 0ߣ૩ ੋؙझী Hi ࢗੑ [(v)H, i, _, _, _, _, _, _, _, _] // ݽف Gap ী ࢗੑغ޲۽ ୶о Gap ࢤࢿ੉ ೙ਃೞ૑ ঋই O(1) ী ৮ܐؽ
  9. Gap Buffer: زੌೠ ਤ஖ Ӕ୊ী ௿۞झఠ݂ػ ബਯ੸ੋ ࢗੑ ߂ ࢏ઁ

    ੘সਸ ೲਊೞח ز੸ ߓৌ 1, ୡӝ Gap ࢤࢿ: O(N) [(v)_, _, _, _, _, _, _, _, _, _] // _ ח Gap, (v) ח അ੤ cursor ܳ աఋն 2. 0ߣ૩ ੋؙझী Hi ࢗੑ [(v)H, i, _, _, _, _, _, _, _, _] // ݽف Gap ী ࢗੑغ޲۽ ୶о Gap ࢤࢿ੉ ೙ਃೞ૑ ঋই O(1) ী ৮ܐؽ 3. 1ߣ૩ ੋؙझ੄ i ઁѢ [H, (v)_, _, _, _, _, _, _, _, _] // cursor ܳ i о ੓ח ਤ஖۽ ৤ӝӝ ਤ೧ O(N) ੉ ѦܻҊ // ੉റ Gap ীࢲ ч ઁѢо ૓೯غ޲۽ O(1) ݅ী ৮ܐؽ (ч ઁѢח ೧׼ чਸ Gap ਵ۽ ߸҃ೞח Ѫਵ۽ ҳഅؾפ׮)
  10. Gap Buffer: زੌೠ ਤ஖ Ӕ୊ী ௿۞झఠ݂ػ ബਯ੸ੋ ࢗੑ ߂ ࢏ઁ

    ੘সਸ ೲਊೞח ز੸ ߓৌ 1, ୡӝ Gap ࢤࢿ: O(N) [(v)_, _, _, _, _, _, _, _, _, _] // _ ח Gap, (v) ח അ੤ cursor ܳ աఋն 2. 0ߣ૩ ੋؙझী Hi ࢗੑ [(v)H, i, _, _, _, _, _, _, _, _] // ݽف Gap ী ࢗੑغ޲۽ ୶о Gap ࢤࢿ੉ ೙ਃೞ૑ ঋই O(1) ী ৮ܐؽ 3. 1ߣ૩ ੋؙझ੄ i ઁѢ [H, (v)_, _, _, _, _, _, _, _, _] // cursor ܳ i о ੓ח ਤ஖۽ ৤ӝӝ ਤ೧ O(N) ੉ ѦܻҊ // ੉റ Gap ীࢲ ч ઁѢо ૓೯غ޲۽ O(1) ݅ী ৮ܐؽ (ч ઁѢח ೧׼ чਸ Gap ਵ۽ ߸҃ೞח Ѫਵ۽ ҳഅؾפ׮) 4. 0ߣ૩ ੋؙझ੄ H ܳ Bye ۽ ߸҃ [(v)B, y, e, _, _, _, _, _, _, _] // cursor ܳ H о ੓ח ਤ஖۽ ৤ӝӝ ਤ೧ O(N) ੉ ѦܻҊ // ੉റ ݽف Gap ীࢲ ч সؘ੉౟о ૓೯غ޲۽ O(1) ݅ী ৮ܐؽ
  11. var isLoading = false @Composable fun Main() { Column {

    // 1ߣ૩ ਤ஖ (അ੤ cursor) Text(text = "Column Data") if (isLoading) { Text(text = "Loading...") } } } Column Text “Column Data” Gap Gap Gap Gap Gap Gap ߣ૩ਤ஖
  12. var isLoading = true @Composable fun Main() { Column {

    // 1ߣ૩ ਤ஖ (੉੹ cursor) Text(text = "Column Data") if (isLoading) { // 2ߣ૩ ਤ஖ (അ੤ cursor) Text(text = "Loading...") } } } Column Text “Column Data” Gap Gap Gap Gap Text “Loading…” ߣ૩ਤ஖ ߣ૩ਤ஖
  13. /** * Gap ਸ ޖदೞҊ ౠ੿ ਤ஖੄ ੺؀੸ੋ ੋؙझܳ оܰఃח

    ېಌੑפ׮. (ےؒ ঘࣁझ ഝࢿച) * * ےؒ ঘࣁझ: ؘ੉ఠܳ ੷੢ೞח ࠶۾ਸ ೠߣী ৈ۞ ѐ ঘࣁझೞח Ѫ੉ ইפۄ ౠ੿ ਤ஖۽ ߄۽ ੽Ӕೞৈ ೠ ߣী ೞա੄ ࠶۾݅ਸ ঘࣁझೞח ߑध */ internal class Anchor(loc: Int) { internal var location = loc val valid get() = location != Int.MIN_VALUE fun toIndexFor(slots: SlotTable) = slots.anchorIndex(this) fun toIndexFor(writer: SlotWriter) = writer.anchorIndex(this) }
  14. var isLoading = true @Composable fun Main() { Column {

    Text(text = "Column Data") if (isLoading) { // Anchor ۽ ߄۽ ੽Ӕ Text(text = "Loading...") } } } Column Text “Column Data” Gap Gap Gap Gap Text “Loading…” "ODIPS۽߄۽੽Ӕ
  15. var isColumn = true @Composable fun Main() { if (isColumn)

    { Column { Text(text = "Column Data") } } else { Row { repeat(10) { index -> Text(text = "Row Data - $index") } } } } Column Text “Column Data” Gap Gap Gap Gap Gap Gap
  16. var isColumn = false @Composable fun Main() { if (isColumn)

    { Column { Text(text = "Column Data") } } else { Row { repeat(10) { index -> Text(text = "Row Data - $index") } } } } Row Text “Row Data - 0” Text “Row Data - 1” Text Text Text “Row Data - 2” “Row Data - 3”
  17. var isLoading = false @Composable fun Main() { Column {

    Text(text = "Column Data") if (isLoading) { Text(text = "Loading...") } } } Column Text “Column Data” Gap Gap Gap Gap Gap Gap Composition
  18. var isLoading = true @Composable fun Main() { Column {

    Text(text = "Column Data") if (isLoading) { Text(text = "Loading...") } } } Column Text “Column Data” Gap Gap Gap Gap Text “Loading…” Recomposition !$PNQPTBCMF੄ݵ١ࢿࠁ੢ ܻஹನ૑࣌ࢤۚ4NBSU3FDPNQPTJUJPO
  19. var isLoading = true @Composable fun Main() { Column {

    Text(text = "Column Data") if (isLoading) { Text(text = "Loading...") } } } Emit Column Text Text
  20. var isLoading = true @Composable fun Main() { Column {

    Text(text = "Column Data") if (isLoading) { Text(text = "Loading...") } } } Materializing
  21. var isLoading = true @Composable fun Main() { Column {

    Text(text = "Column Data") if (isLoading) { Text(text = "Loading...") } } } Column Text “Column Data” Gap Gap Gap Gap Text “Loading…”
  22. val isLoading = mutableStateOf(false) // Snapshot System isLoading.value = true

    @Composable fun Main() { Column { Text(text = "Column Data") if (isLoading) { Text(text = "Loading...") } } } Column Text “Column Data” Gap Gap Gap Gap Text “Loading…”
  23. @Composable fun TextWrapper() { Text(text = "SungbinLand") } dependencies {

    // annotation processor XXX implementation "androidx.compose.foundation:foundation:1.3.0-alpha01" }
  24. @Composable fun TextWrapper() { Text(text = "SungbinLand") } buildFeatures {

    compose true // ஹನૉ ௏ౣܽ ஹ౵ੌ۞ ഝࢿച /** * ஹನૉ ஹ౵ੌ җ੿ਸ ௏ౣܽ ঱য੄ ஹ౵ੌ җ੿ਵ۽ ੐ߓ٘ೞৈ ୊ܻ ࣘبܳ ֫੉Ҋ, য֢ప੉࣌ ೐۽ࣁࢲח ೡ ࣻ হח ֫ਸ ࣻળ੄ ௏٘ ੽Ӕਸ ೞৈ ஹ౵ੌؾפ׮. * ৘ܳ ٜয, ௏ౣܽҗ ஹನૉח ݣ౭೒ۖಬਸ ؀࢚ਵ۽ ೞ޲۽ ஹ౵ੌ җ੿ীࢲ ࢤࢿغח IR ਸ അ੤ ೒ۖಬী ݏח ജ҃ਵ۽ ࣻ੿ೞҊ lowering ਸ ૓೯೤פ׮. */ } // or… gradle.kts ܳ ࢎਊೠ׮ݶ import org.jetbrains.kotlin.gradle.plugin.PLUGIN_CLASSPATH_CONFIGURATION_NAME dependencies { add(PLUGIN_CLASSPATH_CONFIGURATION_NAME, "org.jetbrains.compose.compiler:compiler:$version") }
  25. /** * উ੿ ࢚కח ௼ѱ 3о૑੄ ઑѤਸ ٮܵפ׮. * *

    - ч੉ ߸҃عਸ ҃਋ ஹನ੷࠶ীѱ ঌ۰ઉঠ ೤פ׮. (૊, [State] ۽ ੘زظঠ ೣ) * - ੉੹ ੋझఢझ৬ അ੤ ੋझఢझо زੌ೧ঠ ೤פ׮. * - ݽٚ ҕѐ ೙ٜ٘ب ׮ উ੿ ࢚కৈঠ ೤פ׮. * * ੉ 3о૑ ઑѤਸ ٮܲ׮ݶ ஹನૉח ೧׼ ೙٘о উ੿੸ੋ ࢚కۄҊ ౵ঈೞҊ, * ೧׼ ೙٘੄ ч੉ ߄Շ૑ ঋও׮ݶ ࢎਊػ ஹನ੷࠶੄ ܻஹನ૑࣌ਸ ࢤۚ೤פ׮. * * @see Immutable * @see Stable */ @Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS) @Retention(AnnotationRetention.BINARY) annotation class StableMarker
  26. /** * ࢤࢿػ ੉റ۽ ݽٚ ҕѐ੸ੋ ೙٘о ੺؀ ߸ೞ૑ ঋח׮ח

    Ѫਸ աఋղݴ ௿ېझী ੸ਊؼ ࣻ ੓णפ׮. * * ࢤࢿ ੉റ ч੉ ߸҃غ૑ ঋਵ޲۽ উ੿੄ ୐ ߣ૩ ӏ஗ੋ * "ч੉ ߸҃عਸ ҃਋ ஹನ੷࠶ীѱ ঌ۰ઉঠ ೤פ׮." о ޖदؾפ׮. */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.BINARY) @StableMarker annotation class Immutable fun main() { val list = mutableListOf(1) list.add(2) // ੋझఢझח زੌೞ૑݅ ч੉ ߄Չ ࣻ ੓णפ׮. // @Immutable ਷ ੉۞ೠ ߸҃ب ೲਊೞ૑ ঋणפ׮. }
  27. /** * ч੉ ߸҃ؼ ࣻ ੓ח ࢚క੉ݴ, ੸ਊ ؀࢚ী ٮۄ

    ডрঀ ৉ೡ੉ ׳ۄ૘פ׮. * * ఋੑী ੸ਊػ׮ݶ ୶о ৉ೡ হ੉ [StableMarker] ੄ ৉ೡਸ Ӓ؀۽ оઉцפ׮. * * ೣࣻա ೐۽ಌ౭ী ੸ਊػ׮ݶ [StableMarker] ੄ ৉ೡী ୶оغח ৉ೡ੉ ࢤӤפ׮. * э਷ input ী ੓যࢲח ೦࢚ زੌೠ output ਸ ٜ݅যղݴ(ࣽࣻ ೣࣻ), ೣࣻ੄ ҃਋ ੋ੗ٜ ৉द ݽف উ੿੸ੋ ࢚కۄח Ѫਸ ডࣘ೤פ׮. * ݅ড input ੉ زੌೞ׮ݶ output ژೠ زੌೡ Ѫ੉ӝ ٸޙী ܻஹನ૑࣌ਸ झఈೞѱ ؾפ׮. */ @Target( AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY ) @Retention(AnnotationRetention.BINARY) @StableMarker annotation class Stable
  28. // উ੿ࢿ਷ ੹౵ػ׮. @Immutable interface SungbinLand class SungbinLandImpl : SungbinLand

    // ߈ജೞח SungbinLand о উ੿ ࢚క੉ӝ ٸޙী // ೣࣻী StableMarker о হযب ੉ ೣࣻח উ੿ ࢚క۽ р઱ػ׮. fun provideSungbinLand(): SungbinLand = SungbinLandImpl() // data ੋ੗੄ ఋੑ੉ উ੿ ࢚క੉ӝ ٸޙী data ੋ੗ח উ੿ ࢚కо غҊ, // ੉ ஹನ੷࠶਷ skippable ࢚కо ػ׮. @Composable fun SungbinLandDisplay(data: SungbinLand = provideSungbinLand()) { Text(text = data.toString()) }
  29. // উ੿ࢿ਷ ੹౵ػ׮. interface SungbinLand @Immutable class SungbinLandImpl : SungbinLand

    // ߈ജೞח SungbinLand ী ؀ೠ উ੿ࢿ ੿ࠁо হӝ ٸޙী ੉ ೣࣻח ࠛউ੿ ࢚కо ػ׮. fun provideSungbinLand(): SungbinLand = SungbinLandImpl() // data ੋ੗੄ ఋੑ਷ ࠛউ੿ ࢚క੉૑݅, provideSungbinLand() ೣࣻীࢲ чਸ ઁҕೞחؘ ࢎਊೞח // SungbinLandImpl ௿ېझח উ੿ ࢚క੉ӝ ٸޙী data ੋ੗੄ ӝࠄ ч੉ উ੿ ࢚కۄ // ੉ ஹನ੷࠶਷ skippable ࢚కо ػ׮. (ױ, ৈ੹൤ data ੋ੗ח ࠛউ੿ ࢚క۽ թח׮) @Composable fun SungbinLandDisplay(data: SungbinLand = provideSungbinLand()) { Text(text = data.toString()) }
  30. /** * ஹ౵ੌ द੼ী ݽٚ ௿ېझٜ੄ উ੿ࢿਸ ੗زਵ۽ ୶ۿ೤פ׮. *

    * @param parameters উ੿ࢿਸ ୶ۿೞחؘ ب਑੉ ؼ ࣻ ੓ѱ ੋ੗ٜ੄ ࠺౟݃झ௼ܳ աఋշפ׮. */ @ComposeCompilerApi @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.BINARY) annotation class StabilityInferred(val parameters: Int) // ਬੌೠ ೙٘ੋ value о উ੿ ࢚క੉Ҋ ࠛ߸ೞӝ ٸޙী Name ௿ېझח উ੿ ࢚క۽ ౸ױػ׮. class Name(val value: String) // ਬੌೠ ೙٘ੋ value ੄ ఋੑ੉ ઁ֎ܼ੉ۄ ఋੑਸ ౸ױೡ ࣻ হӝী ࢎ੹ী ࠺౟݃झఊػ чਸ ӝળਵ۽ উ੿ ࢚కܳ ୶ۿೠ׮. // ೞ૑݅ ೙٘о о߸ ࢚క੉ӝ ٸޙী T ఋੑ੉ উ੿੉ৈب NameWithGeneric ௿ېझח ࠛউ੿ ࢚క۽ ౸ױػ׮. class NameWithGeneric<T>(var value: T) ௿ېझউ੿ࢿ୶ۿ j j j j
  31. fun earth() { print(LiveLiterals$EarthKt.`getString$arg-0$call-print$fun-earth`()) } object LiveLiterals$EarthKt { var `String$arg-0$call-print$fun-earth`

    = "Bye World" var `State$String$arg-0$call-print$fun-earth`: MutableState<String>? = null fun `getString$arg-0$call-print$fun-earth`(): String { val field = this.`String$arg-0$call-print$fun-earth` val state = if (field == null) { val tmp = liveLiteral( "String$arg-0$call-print$fun-earth", this.`String$arg-0$call-print$fun-earth` ) this.`String$arg-0$call-print$fun-earth` = tmp tmp } else field return field.value } }
  32. fun earth() { print(LiveLiterals$EarthKt.`getString$arg-0$call-print$fun-earth`()) } object LiveLiterals$EarthKt { var `String$arg-0$call-print$fun-earth`

    = "Bye World" var `State$String$arg-0$call-print$fun-earth`: MutableState<String>? = null fun `getString$arg-0$call-print$fun-earth`(): String { val field = this.`String$arg-0$call-print$fun-earth` val state = if (field == null) { val tmp = liveLiteral( "String$arg-0$call-print$fun-earth", this.`String$arg-0$call-print$fun-earth` ) this.`String$arg-0$call-print$fun-earth` = tmp tmp } else field return field.value } }
  33. fun earth() { print(LiveLiterals$EarthKt.`getString$arg-0$call-print$fun-earth`()) } object LiveLiterals$EarthKt { var `String$arg-0$call-print$fun-earth`

    = "Bye World" var `State$String$arg-0$call-print$fun-earth`: MutableState<String>? = null fun `getString$arg-0$call-print$fun-earth`(): String { val field = this.`String$arg-0$call-print$fun-earth` val state = if (field == null) { val tmp = liveLiteral( "String$arg-0$call-print$fun-earth", this.`String$arg-0$call-print$fun-earth` ) this.`String$arg-0$call-print$fun-earth` = tmp tmp } else field return field.value } }
  34. fun earth() { print(LiveLiterals$EarthKt.`getString$arg-0$call-print$fun-earth`()) } object LiveLiterals$EarthKt { var `String$arg-0$call-print$fun-earth`

    = "Bye World" var `State$String$arg-0$call-print$fun-earth`: MutableState<String>? = null fun `getString$arg-0$call-print$fun-earth`(): String { val field = this.`String$arg-0$call-print$fun-earth` val state = if (field == null) { val tmp = liveLiteral( "String$arg-0$call-print$fun-earth", this.`String$arg-0$call-print$fun-earth` ) this.`String$arg-0$call-print$fun-earth` = tmp tmp } else field return field.value } }
  35. fun earth() { print(LiveLiterals$EarthKt.`getString$arg-0$call-print$fun-earth`()) } object LiveLiterals$EarthKt { var `String$arg-0$call-print$fun-earth`

    = "Bye World" var `State$String$arg-0$call-print$fun-earth`: MutableState<String>? = null fun `getString$arg-0$call-print$fun-earth`(): String { val field = this.`String$arg-0$call-print$fun-earth` val state = if (field == null) { val tmp = liveLiteral( "String$arg-0$call-print$fun-earth", this.`String$arg-0$call-print$fun-earth` ) this.`String$arg-0$call-print$fun-earth` = tmp tmp } else field return field.value } }
  36. fun earth() { print(LiveLiterals$EarthKt.`getString$arg-0$call-print$fun-earth`()) } object LiveLiterals$EarthKt { var `String$arg-0$call-print$fun-earth`

    = "Bye World" var `State$String$arg-0$call-print$fun-earth`: MutableState<String>? = null fun `getString$arg-0$call-print$fun-earth`(): String { val field = this.`String$arg-0$call-print$fun-earth` val state = if (field == null) { val tmp = liveLiteral( "String$arg-0$call-print$fun-earth", this.`String$arg-0$call-print$fun-earth` ) this.`String$arg-0$call-print$fun-earth` = tmp tmp } else field return field.value } }
  37. fun earth() { print(LiveLiterals$EarthKt.`getString$arg-0$call-print$fun-earth`()) } object LiveLiterals$EarthKt { var `String$arg-0$call-print$fun-earth`

    = "Bye World" var `State$String$arg-0$call-print$fun-earth`: MutableState<String>? = null fun `getString$arg-0$call-print$fun-earth`(): String { val field = this.`String$arg-0$call-print$fun-earth` val state = if (field == null) { val tmp = liveLiteral( "String$arg-0$call-print$fun-earth", this.`String$arg-0$call-print$fun-earth` ) this.`String$arg-0$call-print$fun-earth` = tmp tmp } else field return field.value } }
  38. private val liveLiteralCache = HashMap<String, MutableState<Any?>>() @InternalComposeApi @ComposeCompilerApi fun <T>

    liveLiteral(key: String, value: T): State<T> { return liveLiteralCache.getOrPut(key) { mutableStateOf(value) } as State<T> }
  39. @InternalComposeApi fun updateLiveLiteralValue(key: String, value: Any?) { var needToUpdate =

    true val stateObj = liveLiteralCache.getOrPut(key) { needToUpdate = false mutableStateOf(value) } if (needToUpdate) { stateObj.value = value } }
  40. private fun findEffectiveRecomposeScope(group: Int): RecomposeScopeImpl? { var current = group

    while (current > 0) { for (data in DataIterator(this, current)) { if (data is RecomposeScopeImpl) { return data } } current = groups.parentAnchor(current) } return null }
  41. // @Composable XXX fun earth() { print(LiveLiterals$EarthKt.`getString$arg-0$call-print$fun-earth`()) } object LiveLiterals$EarthKt

    { var `String$arg-0$call-print$fun-earth` = "Bye World" var `State$String$arg-0$call-print$fun-earth`: MutableState<String>? = null fun `getString$arg-0$call-print$fun-earth`(): String { val field = this.`String$arg-0$call-print$fun-earth` val state = if (field == null) { val tmp = liveLiteral( "String$arg-0$call-print$fun-earth", this.`String$arg-0$call-print$fun-earth` ) this.`String$arg-0$call-print$fun-earth` = tmp tmp } else field return field.value } }
  42. /** * LiveLiteral ੉ ெઉ ੓ח ҃਋ীب ੸ਊغח ߧਤ ղীࢲ

    LiveLiteral ਸ ࢤࢿೞ૑ ঋب۾ ஹನૉ ஹ౵ੌ۞ী ಴दೞח ؘ ࢎਊؾפ׮. */ @Target( AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.CLASS, AnnotationTarget.FILE ) @Retention(AnnotationRetention.SOURCE) annotation class NoLiveLiterals // @file:NoLiveLiterals @NoLiveLiterals fun earth() { print("Bye World") }
  43. $PNQPTFS઱ੑ j j j j // ஹ౵ੌ ੹ @Composable fun

    TextWrapper() { Text(text = "SungbinLand") } // ஹ౵ੌ റ, Composer: ஹನૉ ۠ఋ੐੉ ஹನ੷࠶җ ࢚ഐ ੘ਊ ೡ ࣻ ੓ѱ ب৬઱ח ੋఠಕ੉झ @Composable fun TextWrapper(composer: Composer, changed: Int) { composer.startRestartGroup(-137853230) composer.sourceInformation("C(TextWrapper)22@513L26:MainActivity.kt#dmu2em") if (changed == 0 && composer.skipping) { composer.skipToGroupEnd() } else { Text(text = "SungbinLand") } composer.endRestartGroup()?.updateScope { composer, _ -> TextWrapper(composer, changed or 1) } }
  44. @Composable fun TextWrapper(composer: Composer, changed: Int) { composer.startRestartGroup(-137853230) composer.sourceInformation("C(TextWrapper)22@513L26:MainActivity.kt#dmu2em") if

    (changed == 0 && composer.skipping) { composer.skipToGroupEnd() } else { Text(text = "SungbinLand") } composer.endRestartGroup()?.updateScope { composer, _ -> TextWrapper(composer, changed or 1) } } Group ஹನ੷࠶Ӓܛࢤࢿ j j j j
  45. @Composable fun Main() { Column { Text(text = "Column Data")

    } } Column Text “Column Data” Gap Gap Gap Gap Gap Gap
  46. @Composable fun Main() { Column { Text(text = "Column Data")

    } } “Column Data” Gap Gap Gap Gap Gap Gap Group Group
  47. // RestartableGroup: ܻஹನ૑࣌੉ ੌযզ ࣻ ੓ח ஹನ੷࠶ ઱ਤ۽ ࢤࢿػ׮. //

    ߹ب੄ ২࣌੉ হ׮ݶ ݽٚ ஹನ੷࠶ী ؀೧ ࢤࢿغח Ӓܛ੉Ҋ, // ܻஹನ૑࣌ ೞח ߑߨਸ оܰ஘׮. // ݽٚ RestartableGroup ਷ ೧׼ ߧਤ ݅ఀ // ੗୓੄ ܻஹನ૑࣌ झ௏೐(RecomposeScope)ܳ ഋࢿೠ׮. @Composable fun RestartableContainer() { Text(text = "SungbinLand") } RestartableGroup “SungbinLand” Gap Gap Gap Gap Gap Gap RestartableGroup 3FTUBSUBCMF$POUBJOFS  3FDPNQPTF4DPQF 5FYU  3FDPNQPTF4DPQF
  48. // ReplaceableGroup: ࠙ӝী ٮۄ ੤ߓ஖ ؼ ࣻ ੓ח ஹನ੷࠶ ઱ਤ۽

    ࢤࢿػ׮. // Ӓܛਸ Ү୓೧ঠ ೡ ٸ ੘ࢿػ ؘ੉ఠܳ ੿ܻೞח ߑߨਸ оܰ஘׮. @Composable fun ReplaceableContainer(isColumn: Boolean = true) { when (isColumn) { true -> Text(text = "Column") else -> Text(text = "Row") } } RestartableGroup “Column” Gap Gap Gap Gap Gap ReplaceableGroup 3FQMBDFBCMF$POUBJOFS XIFO RestartableGroup 5FYU
  49. /** * ஹನ੷࠶੉ ߓ஖ػ ਤ஖о ׳ۄ૑ݶ ਤ஖ ݫݽ੉ઁ੉࣌੄ key о

    ׳ۄઉࢲ ؘ੉ఠо ୡӝചؾפ׮. * ؘ੉ఠܳ ਬ૑ೠ ࢚క۽ ਤ஖ܳ ৤ӝӝ ਤ೧ࢶ key ஹನ੷࠶ਸ ੉ਊ೧ * ਤ஖ ݫݽ੉ઁ੉࣌ীࢲ ଵҊೡ key ܳ ૒੽ ੿੄೧ঠ ೤פ׮. * * key ஹನ੷࠶ਸ ੉ਊ೧ ߓ஖ػ ஹನ੷࠶਷ ઱ਤ۽ MovableGroup ੉ ࢤࢿؾפ׮. * MovableGroup ਷ ஹನ੷࠶੉ ਤ஖ ݫݽ੉ઁ੉࣌ key ৬ ؘ੉ఠܳ ೦࢚ ࠁઓೞݴ * ੉زೞח ߑߨਸ оܰ஝פ׮. */ @Composable inline fun <T> key( vararg keys: Any?, block: @Composable () -> T ) @Composable fun MovableContainer() { key(Any()) { Text(text = "Key") } } RestartableGroup “Key” Gap Gap Gap Gap Gap MovableGroup .PWBCMF$POUBJOFS LFZ RestartableGroup 5FYU
  50. 🎨 🖼️ 🖌️ 🧰 Material ݠఠܻ঴٣੗ੋदझమ 5FYU #VUUPO #PUUPN4IFFU $IJQ

    "MFSU%JBMPH *DPOT 4VSGBDF Foundation о੢ӝୡ੸ੋ٣੗ੋ -B[Z-JTU $PMVNO $BOWBT 4IBQF (FTUVSFT 0WFSTDSPMM&GGFDU UI ஹನૉ6*5PPMLJU੄ӝࠄࢸ҅ -BZPVU %JBMPH $PNQPTF7JFX"EBQUFS 1SFWJFX"DUJWJUJZ Runtime ஹನૉউ٘۽੉٘োѾ *OWBMJEBUJPO 4OBQTIPU4ZTUFN 4MPU5BCMF -JWF-JUFSBM
  51. class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState) setContent { Text(text = "SungbinLand") } } }
  52. // ஹನૉ ۠ఋ੐җ UI ੄ োѾ fun ComponentActivity.setContent( parent: CompositionContext?

    = null, content: @Composable () -> Unit ) { ComposeView(this).apply { setParentCompositionContext(parent) setContent(content) setOwners() setContentView(this, DefaultActivityContentLayoutParams) } }
  53. // ComposeView#setContent ۽ ੉ ೣࣻо प೯ؽ private fun ensureCompositionCreated() {

    setContent(/* Recomposer о ٜ݅য૑Ҋ ઱ੑؾפ׮ */) { content() } }
  54. /** * ܻஹನ૑࣌ਸ ࣻ೯ೞҊ ೞա ੉࢚੄ ஹನ੷࠶ী সؘ੉౟ܳ ੸ਊೞӝ ਤೠ

    झா઴۞ ੑפ׮. */ class Recomposer( effectCoroutineContext: CoroutineContext ) : CompositionContext() /** * Handler ௒ߔ ژח Choreographer ੄ গפݫ੉࣌ ೐ۨ੐ ױ҅ ઺ * ݢ੷ بېೞח ױ҅ীࢲ ٣झಁ஖ܳ ࣻ೯ೞח CoroutineDispatcher ੑפ׮. */ class AndroidUiDispatcher private constructor( val choreographer: Choreographer, private val handler: Handler ) : CoroutineDispatcher()
  55. /** * ܻஹನ૑࣌ਸ ࣻ೯ೞҊ ೞա ੉࢚੄ ஹನ੷࠶ী সؘ੉౟ܳ ੸ਊೞӝ ਤೠ

    झா઴۞ ੑפ׮. */ class Recomposer( effectCoroutineContext: CoroutineContext ) : CompositionContext() /** * Handler ௒ߔ ژח Choreographer ੄ গפݫ੉࣌ ೐ۨ੐ ױ҅ ઺ * ݢ੷ بېೞח ױ҅ীࢲ ٣झಁ஖ܳ ࣻ೯ೞח CoroutineDispatcher ੑפ׮. */ class AndroidUiDispatcher private constructor( val choreographer: Choreographer, private val handler: Handler ) : CoroutineDispatcher()
  56. suspend fun runRecomposeAndApplyChanges() = recompositionRunner { parentFrameClock -> val toRecompose

    = mutableListOf<RecomposeScope>() while (shouldKeepRecomposing) { awaitWorkAvailable() parentFrameClock.withFrameNanos { frameTime -> try { toRecompose.fastForEach { composition -> performRecompose(composition) } } finally { toRecompose.clear() } } } }
  57. private suspend fun recompositionRunner(block: suspend CoroutineScope.(parentFrameClock: MonotonicFrameClock) -> Unit) {

    // Recomposer ীࢲ ߉਷ Choreographer ੄ ېಌੋ MonotonicFrameClock ܳ оઉৡ׮. val parentFrameClock: MonotonicFrameClock = coroutineContext.monotonicFrameClock withContext(broadcastFrameClock) { // broadcastFrameClock: ஹನૉ ۠ఋ੐ীࢲ ҟ৉ਵ۽ ࢎਊغח MonotonicFrameClock ੄ ېಌ Snapshot.registerApplyObserver { _, _ -> // Snapshot ੄ write ੉߮౟ܳ ߉ח׮. deriveStateLocked()?.resume(Unit) } coroutineScope { block(parentFrameClock) } } }
  58. private suspend fun recompositionRunner(block: suspend CoroutineScope.(parentFrameClock: MonotonicFrameClock) -> Unit) {

    // Recomposer ীࢲ ߉਷ Choreographer ੄ ېಌੋ MonotonicFrameClock ܳ оઉৡ׮. val parentFrameClock: MonotonicFrameClock = coroutineContext.monotonicFrameClock withContext(broadcastFrameClock) { // broadcastFrameClock: ஹನૉ ۠ఋ੐ীࢲ ҟ৉ਵ۽ ࢎਊغח MonotonicFrameClock ੄ ېಌ Snapshot.registerApplyObserver { _, _ -> // Snapshot ੄ write ੉߮౟ܳ ߉ח׮. deriveStateLocked()?.resume(Unit) } coroutineScope { block(parentFrameClock) } } }
  59. suspend fun runRecomposeAndApplyChanges() = recompositionRunner { parentFrameClock -> val toRecompose

    = mutableListOf<RecomposeScope>() // ܻஹನ૑࣌੉ ೙ਃೠ RecomposeScope о ׸ӟ׮. (׸ח җ੿ ࢤۚ) while (shouldKeepRecomposing) { // shouldKeepRecomposing: Recomposer о ܻஹನ૑࣌ ਃ୒ਸ х૑೧ঠ ೞח૑ܳ աఋմ׮. awaitWorkAvailable() // ࢜۽਍ ܻஹನ૑࣌ ਃ୒੉ ੓ਸ ٸ ө૑ suspend ࢚క۽ ӝ׮ܽ׮. parentFrameClock.withFrameNanos { frameTime -> // Choreographer#postFrameCallback ਸ ഐ୹ೠ׮. try { toRecompose.fastForEach { composition -> // RecomposeScope ܳ ࣽഥೞݴ performRecompose(composition) // ܻஹನ૑࣌ ૓೯! } } finally { toRecompose.clear() } } } }
  60. private suspend fun awaitWorkAvailable() { suspendCancellableCoroutine { co -> if

    (hasSchedulingWork) { // ؀ӝ઺ੋ ܻஹನ૑࣌ ਃ୒੉ ੓׮ݶ ߄۽ resume ೞҊ co.resume(Unit) } else { // ؀ӝ઺ੋ ܻஹನ૑࣌ ਃ୒੉ হ׮ݶ workContinuation ਵ۽ CancellableContinuation ੷੢ റ suspend ਬ૑ workContinuation = co } } }
  61. private fun deriveStateLocked(): CancellableContinuation<Unit>? { // ࠁܨ ઺ੋ ੘স: ܻஹನ૑࣌

    ਃ୒ ١١ ஹನૉ ۠ఋ੐ ղࠗীࢲ ૓೯غח ৈ۞ ੘স ਃ୒ val newState = when { /* അ੤ ࠁܨ ઺ੋ ੘স ৈࠗী ٮۄ ࢜۽਍ ࢚క ҅࢑ */ } return if (newState == State.PendingWork) { // ࠁܨ ઺ੋ ੘স੉ ੓׮ݶ workContinuation.also { // workContinuation ߈ജ ߂ workContinuation ୡӝച workContinuation = null } } else null }
  62. private suspend fun recompositionRunner(block: suspend CoroutineScope.(parentFrameClock: MonotonicFrameClock) -> Unit) {

    val parentFrameClock = coroutineContext.monotonicFrameClock withContext(broadcastFrameClock) { Snapshot.registerApplyObserver { _, _ -> deriveStateLocked()?.resume(Unit) } coroutineScope { block(parentFrameClock) } } }
  63. suspend fun runRecomposeAndApplyChanges() = recompositionRunner { parentFrameClock -> val toRecompose

    = mutableListOf<RecomposeScope>() while (shouldKeepRecomposing) { awaitWorkAvailable() // ܻஹನ૑࣌ ਃ୒੉ ੓ਸ ٸ ө૑ suspend parentFrameClock.withFrameNanos { frameTime -> // ׮਺ ೐ۨ੐ীࢲ try { toRecompose.fastForEach { composition -> performRecompose(composition) } // Recomposition! } finally { toRecompose.clear() } } } } private suspend fun recompositionRunner(block: suspend CoroutineScope.(parentFrameClock: MonotonicFrameClock) -> Unit) { val parentFrameClock = coroutineContext.monotonicFrameClock withContext(broadcastFrameClock) { Snapshot.registerApplyObserver { _, _ -> deriveStateLocked()?.resume(Unit) } // Snapshot ч ߸҃੉ ੓ਸ ٸ resume coroutineScope { block(parentFrameClock) } } }
  64. // ComposeView#setContent ۽ ੉ ೣࣻо प೯ؽ private fun ensureCompositionCreated() {

    setContent(/* Recomposer о ٜ݅য૑Ҋ ઱ੑؾפ׮ */) { content() } }
  65. // this: Composer private fun doCompose(content: @Composable () -> Unit)

    { startRoot() // ठܶ ప੉࠶ ୡӝച startGroup() // ஹನ੷࠶੉ ٜযт Ӓܛ ࢤࢿ invokeComposable(this, content) endGroup() endRoot() } // performRecompose ب ѾҴ ੉ ೣࣻܳ प೯ೠ׮. internal actual fun invokeComposable(composer: Composer, composable: @Composable () -> Unit) { val realFn = composable as Function2<Composer, Int, Unit> realFn(composer, 1) } Root Group Composable Gap Gap Gap Gap Gap Gap
  66. CVJMENFUSJDT // ஹ౵ੌ۞о х૑ೠ ஹನ੷࠶ ೣٜࣻ੄ ੿ࠁܳ աఋմ׮. kotlinOptions {

    freeCompilerArgs += [ "-P", "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + "${rootProject.file(".").absolutePath}/report/compose-metrics" ] }
  67. <ݽٕݺ>@<࠽٘ఋੑ>NPEVMFKTPO { { "skippableComposables": 48, // skippable ࢚కੋ ஹನ੷࠶ ѐࣻ

    "restartableComposables": 67, "readonlyComposables": 0, "totalComposables": 67, // ੹୓ ஹನ੷࠶ ѐࣻ "restartGroups": 67, "totalGroups": 72, "staticArguments": 130, "certainArguments": 28, "knownStableArguments": 793, // উ੿ ࢚క۽ ঌ۰૓ ੋ੗ ѐࣻ "knownUnstableArguments": 30, // ࠛউ੿ ࢚క۽ ঌ۰૓ ੋ੗ ѐࣻ "unknownStableArguments": 8, "totalArguments": 831, "markedStableClasses": 0, "inferredStableClasses": 16, // উ੿ ࢚క۽ ୶ۿػ ௿ېझ ѐࣻ "inferredUnstableClasses": 2, // ࠛউ੿ ࢚క۽ ୶ۿػ ௿ېझ ѐࣻ "inferredUncertainClasses": 0, "effectivelyStableClasses": 16, "totalClasses": 18, "memoizedLambdas": 54, "singletonLambdas": 5, "singletonComposableLambdas": 8, "composableLambdas": 31, "totalLambdas": 89 }
  68. CVJMESFQPSUT // ஹ౵ੌ۞о х૑ೠ ஹನ੷࠶ ೣٜࣻ੉ ࢎਊ઺ੋ ௿ېझ৬ ੋ੗ী ؀ೠ

    উ੿ࢿ ੿ࠁܳ աఋմ׮. kotlinOptions { freeCompilerArgs += [ "-P", "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + "${rootProject.file(".").absolutePath}/report/compose-reports" ] }
  69. <ݽٕݺ>@<࠽٘ఋੑ>DMBTTFTUYU /* ——— classes ——— */ sealed class UiState {

    object Loading : UiState() object Done : UiState() data class Exception(val throwable: Throwable) : UiState() } /* ——— reports ——— */ stable class Loading { <runtime stability> = Stable } stable class Done { <runtime stability> = Stable } unstable class Exception { unstable val throwable: Throwable <runtime stability> = Unstable }
  70. <ݽٕݺ>@<࠽٘ఋੑ>DPNQPTBCMFTDTW /* ——— composables ——— */ @Composable fun DisplayText(text: String

    = "Hi") { Text(text = text) } @Composable fun DisplayTexts(texts: List<String>) { Text(text = texts.joinToString()) } /* ——— reports ——— */
  71. <ݽٕݺ>@<࠽٘ఋੑ>DPNQPTBCMFTUYU /* ——— composables ——— */ @Composable fun DisplayText(text: String

    = "Hi") { Text(text = text) } @Composable fun DisplayTexts(texts: List<String>) { Text(text = texts.joinToString()) } /* ——— reports ——— */ restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun DisplayText( stable text: String? = @dynamic LiveLiterals$MainActivityKt.String$param-text$fun-DisplayText() ) restartable /* skippable ੉ হ਺ */ scheme("[androidx.compose.ui.UiComposable]") fun DisplayTexts( unstable texts: List<String> )
  72. <ݽٕݺ>@<࠽٘ఋੑ>DPNQPTBCMFTUYU /* ——— composables ——— */ @Composable fun DisplayText(text: String

    = "Hi") { Text(text = text) } @Composable fun DisplayTexts(texts: List<String>) { Text(text = texts.joinToString()) } /* ——— reports ——— */ restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun DisplayText( stable text: String? = @dynamic LiveLiterals$MainActivityKt.String$param-text$fun-DisplayText() ) restartable scheme("[androidx.compose.ui.UiComposable]") fun DisplayTexts( unstable texts: List<String> )
  73. <ݽٕݺ>@<࠽٘ఋੑ>DPNQPTBCMFTUYU /* ——— composables ——— */ @NoLiveLiterals // new @Composable

    fun DisplayText(text: String = "Hi") { Text(text = text) } @Composable fun DisplayTexts(texts: List<String>) { Text(text = texts.joinToString()) } /* ——— reports ——— */ restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun DisplayText( stable text: String? = @static "Hi" ) restartable scheme("[androidx.compose.ui.UiComposable]") fun DisplayTexts( unstable texts: List<String> )
  74. EPOVUIPMFTLJQQJOH setContent { var number by remember { mutableStateOf(0) }

    println("setContent recomposition") Text( modifier = Modifier.clickable { number++ }, text = number.toString() ).also { println("Text recomposition") } } /* ܻஹನ૑࣌੉ য٣ী ૓೯ؼөਃ? 1, setContent content ৔৉ 2. Text 3. setContent content ৔৉ + Text */
  75. EPOVUIPMFTLJQQJOH setContent { var number by remember { mutableStateOf(0) }

    println("setContent recomposition") Text( modifier = Modifier.clickable { number++ }, text = number.toString() ).also { println("Text recomposition") } } /* [first-composition] setContent recomposition Text recomposition [re-composition] setContent recomposition Text recomposition ੉റ زੌ ۽Ӓ ߈ࠂ */
  76. EPOVUIPMFTLJQQJOH setContent { var number by remember { mutableStateOf(0) }

    println("setContent recomposition") Button(onClick = { number++ }) { Text( text = number.toString() ).also { println("Text recomposition") } }.also { println("Button recomposition") } } /* [first-composition] setContent recomposition Text recomposition Button recomposition [re-composition] Text recomposition ੉റ زੌ ۽Ӓ ߈ࠂ */
  77. EPOVUIPMFTLJQQJOH // ஹ౵ੌ ੹ @Composable fun TextWrapper(text: String) { Text(text

    = text) } // ஹ౵ੌ റ (೨ब ࠗ࠙݅ ಴द) @Composable fun TextWrapper(composer: Composer, text: String) { composer.startRestartGroup(-199242123) // ղࠗীࢲ addRecomposeScope() ۽ ܻஹನ૑࣌ झ௏೐ܳ ୶оೞҊ ੓਺ Text(text = text) composer.endRestartGroup() }
  78. EPOVUIPMFTLJQQJOH setContent { var number by remember { mutableStateOf(0) }

    println("setContent recomposition") Text( modifier = Modifier.clickable { number++ }, text = number.toString() ).also { println("Text recomposition") } } setContent { var number by remember { mutableStateOf(0) } println("setContent recomposition") Button(onClick = { number++ }) { Text( text = number.toString() ).also { println("Text recomposition") } }.also { println("Button recomposition") } } Text RecomposeScope 
 Text RecomposeScope 

  79. EPOVUIPMFTLJQQJOH setContent { var number by remember { mutableStateOf(0) }

    println("setContent recomposition") Button(onClick = { number++ }) { Text( text = number.toString() ).also { println("Text recomposition") } }.also { println("Button recomposition") } } Text RecomposeScope 
 Button RecomposeScope
  80. 4UBCJMJUZ4ZTUFN setContent { var number by remember { mutableStateOf(1) }

    TextWrapper( modifier = Modifier.clickable { number++ }, text = number.toString() ) } @Composable fun TextWrapper( modifier: Modifier = Modifier, text: String ) { Text(modifier = modifier, text = text) }
  81. 4UBCJMJUZ4ZTUFN setContent { var number by remember { mutableStateOf(1) }

    TextWithLambda( modifier = Modifier.clickable { number++ }, text = { number.toString() } ) } @Composable fun TextWithLambda( modifier: Modifier = Modifier, text: () -> String // Function0<String> ) { Text(modifier = modifier, text = text()) }
  82. NPWBCMF$POUFOU0G val content = remember<@Composable () -> Unit> { {

    repeat(2) { Box(modifier = Modifier.size(100.dp).background(color = Color.Green)) } } } Column { Button(onClick = { isRow = !isRow }) { Text(text = "Switch") } if (isRow) { Row { content() } } else { Column { content() } } }
  83. NPWBCMF$POUFOU0G val content = remember { movableContentOf { // movableContentWithReceiverOf

    repeat(2) { Box(modifier = Modifier.size(100.dp).background(color = Color.Green)) } } } Column { Button(onClick = { isRow = !isRow }) { Text(text = "Switch") } if (isRow) { Row { content() } } else { Column { content() } } }
  84. !3FBE0OMZ$PNQPTBCMF object MaterialTheme { val colors: Colors @Composable @ReadOnlyComposable get()

    = LocalColors.current val typography: Typography @Composable @ReadOnlyComposable get() = LocalTypography.current // … } @Composable @ReadOnlyComposable fun stringResource(@StringRes id: Int): String { val resources = resources() return resources.getString(id) }
  85. !/PO3FTUBSUBCMF$PNQPTBCMF @Composable @NonRestartableComposable fun DisposableEffect(key1: Any?, effect: DisposableEffectScope.() -> DisposableEffectResult)

    { remember(key = key1) { DisposableEffectImpl(effect) } } @Composable @NonRestartableComposable fun Image( modifier: Modifier = Modifier, colorFilter: ColorFilter? = null, imageVector: ImageVector, contentDescription: String?, alpha: Float = DefaultAlpha, alignment: Alignment = Alignment.Center, contentScale: ContentScale = ContentScale.Fit ) { Image( modifier = modifier, alignment = alignment, contentScale = contentScale, alpha = alpha, colorFilter = colorFilter, painter = rememberVectorPainter(imageVector), contentDescription = contentDescription ) }
  86. TUBUJD$PNQPTJUJPO-PDBM0G val LocalContext = staticCompositionLocalOf<Context> { noLocalProvidedFor("LocalContext") } val LocalClipboardManager

    = staticCompositionLocalOf<ClipboardManager> { noLocalProvidedFor("LocalClipboardManager") } val LocalDensity = staticCompositionLocalOf<Density> { noLocalProvidedFor("LocalDensity") } val LocalFocusManager = staticCompositionLocalOf<FocusManager> { noLocalProvidedFor("LocalFocusManager") }
  87. #BTFMJOFQSPGJMFT .BDSPCFODINBSLݽٕࢸ੿ ௏٘੘ࢿ CBTFMJOFQSPGJMFTࢤࢿ  @ExperimentalBaselineProfilesApi @RunWith(AndroidJUnit4::class) class BaselineProfileGenerator {

    @get:Rule val baselineProfileRule = BaselineProfileRule() @Test fun startup() = baselineProfileRule.collectBaselineProfile( packageName = AppPackageName ) { pressHome() startActivityAndWait() } }
  88. #BTFMJOFQSPGJMFT .BDSPCFODINBSLݽٕࢸ੿ ௏٘੘ࢿ CBTFMJOFQSPGJMFT੸ਊ੹റஏ੿  @RunWith(AndroidJUnit4::class) class BaselineProfileBenchmark { @get:Rule

    val benchmarkRule = MacrobenchmarkRule() // … private fun startup(compilationMode: CompilationMode) { benchmarkRule.measureRepeated( packageName = AppPackageName, metrics = listOf(StartupTimingMetric()), iterations = 10, startupMode = StartupMode.COLD, compilationMode = compilationMode ) { pressHome() startActivityAndWait() } } }
  89. #BTFMJOFQSPGJMFT .BDSPCFODINBSLݽٕࢸ੿ ௏٘੘ࢿ CBTFMJOFQSPGJMFT੸ਊ੹റஏ੿  @RunWith(AndroidJUnit4::class) class BaselineProfileBenchmark { @get:Rule

    val benchmarkRule = MacrobenchmarkRule() @Test fun startupNoCompilation() { startup(compilationMode = CompilationMode.None()) // JIT ஹ౵ੌ } @Test fun startupBaselineProfile() { startup(compilationMode = CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Require)) // AOT ஹ౵ੌ } // … }