{"id":2839,"date":"2025-11-24T14:05:08","date_gmt":"2025-11-24T05:05:08","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=2839"},"modified":"2025-11-24T20:47:05","modified_gmt":"2025-11-24T11:47:05","slug":"kotlinui-sharing-ui-state-and-variables","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2025\/11\/24\/kotlinui-sharing-ui-state-and-variables\/","title":{"rendered":"[Kotlin]UI\uc0c1\ud0dc\uc640 \ubcc0\uc218\ub97c \uacf5\uc720\ud558\uae30 \/ Sharing UI state and variables"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb \ud504\ub85c\uc81d\ud2b8 \uba85\uc774 parentchildview\uc778 \uacbd\uc6b0 \uc785\ub2c8\ub2e4.<br>If the project name is parentchildview.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb<code>viewModel()<\/code>:<br> <code>Composable\uc5d0\uc11c ViewModel\uc744 \uac00\uc838\uc624\uac70\ub098 \uc0dd\uc131\ud558\uace0 \uc7ac\uc0ac\uc6a9\ud558\ub3c4\ub85d \ud574\uc90d\ub2c8\ub2e4.<\/code><br>SwiftUI\uc5d0\uc11c <code>@StateObject<\/code> , <code>@ObservedObject<\/code>\uc640 \uc720\uc0ac\ud55c \uae30\ub2a5\uc744 \uc218\ud589\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<p>Allows you to import, create, and reuse ViewModels from Composable. It performs similar functions to @StateObject and @ObservedObject in SwiftUI.<\/p>\n\n\n\n<p>Parent \ubdf0\uc5d0\uc11c \uc2e4\ud589\ud558\uace0 Child \ubdf0\uc5d0\uc11c\ub294 \uc2e4\ud589\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.<br>It runs in the Parent view and not in the Child view.<\/p>\n\n\n\n<p>\uc880 \ub354 \uc790\uc138\ud788 \uc124\uba85\ud558\uba74 <br>To explain a bit more<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>val viewModel: CounterViewModel = viewModel() <\/code><\/pre>\n\n\n\n<p>\uc704\uc758 \ucf54\ub4dc\uc5d0\uc11c viewModel()\ud568\uc218\uac00 \ud638\ucd9c\ub418\uba74 Composable\uc5d0\uc11c <code>viewModel&lt;CounterViewModel&gt;()<\/code>\uac00 \uc2e4\ud589\ub429\ub2c8\ub2e4.<br>In the above code, when the viewModel() function is called, viewModel() is executed in Composable.<\/p>\n\n\n\n<p>\uc774 \ub54c ViewModelStore\uc5d0 CounterViewModel\uc778\uc2a4\ud134\uc2a4\uac00 \uc788\ub294\uc9c0 \ud655\uc778\ud558\uace0 \uc788\uc73c\uba74 \ubc18\ud658\ud558\uace0 \uc5c6\uc73c\uba74 \uc778\uc2a4\ud134\uc2a4\ub97c \uc0dd\uc131\ud574\uc11c \ubc18\ud658\ud569\ub2c8\ub2e4.<br>At this time, check if there is a CounterViewModel instance in ViewModelStore, and if so, return it. If not, create an instance and return it.<\/p>\n\n\n\n<p>ViewModelStore\ub294 Compose\ub098 Android ViewModel(Architecture Components ViewModel)\uc744 \uc0ac\uc6a9\ud560 \ub54c \ub9cc \uad00\ub828 \uc778\uc2a4\ud134\uc2a4\ub97c \uc800\uc7a5\ud569\ub2c8\ub2e4.<br>ViewModelStore only stores relevant instances when using Compose or Android ViewModel (Architecture Components ViewModel).<\/p>\n\n\n\n<p>\uacb0\ub860\uc740 viewModel\uc5d0\ub294 CounterViewModel \uc778\uc2a4\ud134\uc2a4 \ucc38\uc870\uac00 \ub4e4\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.<br>The bottom line is that viewModel contains a reference to a CounterViewModel instance.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \uc544\ub798\uc758 \ucf54\ub4dc\ub294 CounterViewModel\uc778\uc2a4\ud134\uc2a4\uc758 count\ubcc0\uc218\uc5d0 collectAsState()\ub97c \uc801\uc6a9\ud558\ub77c\ub294 \uc758\ubbf8\uc785\ub2c8\ub2e4.<br>The code below means to apply collectAsState() to the count variable of the CounterViewModel instance.<\/p>\n\n\n\n<p>collectAsState()\ub294 CounterViewModel \ub0b4\ubd80\uc758 count(StateFlow)\ub97c Compose \uc0c1\ud0dc\ub85c \ubcc0\ud658\ud558\uc5ec UI\uac00 \uc790\ub3d9\uc73c\ub85c \uad00\ucc30\ud558\uac8c \ub9cc\ub4e0\ub2e4\ub294 \uc758\ubbf8\uc785\ub2c8\ub2e4.<br>collectAsState() means that count(StateFlow) inside CounterViewModel will be converted to a Compose state so that the UI can automatically observe it.<\/p>\n\n\n\n<p>\uad00\ucc30\uc774\ub780 \ub2e8\uc21c\ud788 \uc77d\ub294 \uac83\ubfd0\ub9cc \uc544\ub2c8\ub77c \u201c\uac12\uc774 \ubc14\ub00c\uc5c8\uc744 \ub54c UI\uac00 \uc790\ub3d9\uc73c\ub85c \ub2e4\uc2dc \uadf8\ub824\uc9c0\ub3c4\ub85d \uc5f0\uacb0\u201d \ud558\ub294 \uc758\ubbf8\uae4c\uc9c0 \ud3ec\ud568\ud569\ub2c8\ub2e4.<br>Observation doesn&#8217;t just mean reading, it also means &#8220;connecting the UI so that it automatically redraws when a value changes.&#8221;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>val count by viewModel.count.collectAsState()<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>\u2714\ufe0fMainActivity.ky<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.freelifemakers.parentchildview\n\nimport android.os.Bundle\nimport androidx.activity.ComponentActivity\nimport androidx.activity.compose.setContent\nimport androidx.activity.enableEdgeToEdge\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.tooling.preview.Preview\nimport com.freelifemakers.parentchildview.ui.theme.ParentChildViewTheme\n\nclass MainActivity : ComponentActivity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        enableEdgeToEdge()\n        setContent {\n            ParentChildViewTheme {\n                Scaffold(\n                    modifier = Modifier.fillMaxSize()\n                ) { innerPadding -&gt;\n                    \/\/ ParentView \ud638\ucd9c \/ Parent View Call\n                    ParentView(\n                        modifier = Modifier.padding(innerPadding)\n                    )\n                }\n            }\n        }\n    }\n}\n\n\/\/ \uae30\uc874 \ucf54\ub4dc \/ Exsisting code\n@Composable\nfun Greeting(name: String, modifier: Modifier = Modifier) {\n    Text(\n        text = \"Hello $name!\",\n        modifier = modifier\n    )\n}\n\n@Preview(showBackground = true)\n@Composable\nfun GreetingPreview() {\n    ParentChildViewTheme {\n        Greeting(\"Android\")\n    }\n}<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f ParentView.kt<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.freelifemakers.parentchildview\n\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.material3.Button\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.collectAsState\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.unit.dp\nimport androidx.lifecycle.viewmodel.compose.viewModel\n\n@Composable\nfun ParentView(modifier: Modifier = Modifier) {\n    val viewModel: CounterViewModel = viewModel()\n    val count by viewModel.count.collectAsState()\n\n    Column(\n        modifier = modifier.padding(20.dp)\n    ) {\n        Text(\"Parent View Count: $count\", style = MaterialTheme.typography.headlineMedium)\n\n        Spacer(modifier = Modifier.height(8.dp))\n\n        Button(onClick = { viewModel.increase() }) {\n            Text(\"Increase\")\n        }\n\n        Spacer(modifier = Modifier.height(16.dp))\n\n        \/\/ \uc9c0\uc2dd \ubdf0 \ud638\ucd9c \/ Child view call\n        ChildView(viewModel)\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f ChildView.kt<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.freelifemakers.parentchildview\n\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.material3.Button\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.collectAsState\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.unit.dp\n\n@Composable\nfun ChildView(viewModel: CounterViewModel) {\n    val count by viewModel.count.collectAsState()\n\n    Column(\n        modifier = Modifier\n            .padding(16.dp)\n            .fillMaxWidth()\n    ) {\n        Text(\n            \"Child View Count: $count\",\n            style = MaterialTheme.typography.titleMedium\n        )\n\n        Spacer(modifier = Modifier.height(8.dp))\n\n        Button(onClick = { viewModel.increase() }) {\n            Text(\"Increase from Child\")\n        }\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f ViewModel.kt<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.freelifemakers.parentchildview\n\nimport androidx.lifecycle.ViewModel\nimport kotlinx.coroutines.flow.MutableStateFlow\nimport kotlinx.coroutines.flow.StateFlow\nimport kotlinx.coroutines.flow.asStateFlow\n\nclass CounterViewModel : ViewModel() {\n\n    private val _count = MutableStateFlow(0)\n    val count: StateFlow&lt;Int&gt; = _count.asStateFlow()\n\n    fun increase() {\n        _count.value += 1\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f \uc2a4\ud06c\ub9b0\uc0f7 \/ ScreenShot<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"[Swift]UI\uc0c1\ud0dc\uc640 \ubcc0\uc218\ub97c \uacf5\uc720\ud558\uae30 \/ Sharing UI state and variables\" width=\"560\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/J2BpJYR3Qf0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffb \ud504\ub85c\uc81d\ud2b8 \uba85\uc774 parentchildview\uc778 \uacbd\uc6b0 \uc785\ub2c8\ub2e4.If the project name is parentchildview. \ud83d\udc49\ud83c\udffbviewModel(): Composable\uc5d0\uc11c ViewModel\uc744 \uac00\uc838\uc624\uac70\ub098 \uc0dd\uc131\ud558\uace0 \uc7ac\uc0ac\uc6a9\ud558\ub3c4\ub85d \ud574\uc90d\ub2c8\ub2e4.SwiftUI\uc5d0\uc11c @StateObject , @ObservedObject\uc640 \uc720\uc0ac\ud55c \uae30\ub2a5\uc744 \uc218\ud589\ud569\ub2c8\ub2e4. Allows you to import, create, and reuse ViewModels from Composable. It performs similar functions to @StateObject and @ObservedObject in SwiftUI. Parent \ubdf0\uc5d0\uc11c \uc2e4\ud589\ud558\uace0 Child \ubdf0\uc5d0\uc11c\ub294 \uc2e4\ud589\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.It runs in the Parent [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12,1],"tags":[],"class_list":["post-2839","post","type-post","status-publish","format-standard","hentry","category-kotlin","category-uncategorized","missing-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/2839","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=2839"}],"version-history":[{"count":12,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/2839\/revisions"}],"predecessor-version":[{"id":2852,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/2839\/revisions\/2852"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=2839"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=2839"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=2839"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}