{"id":60879,"date":"2024-03-26T09:49:21","date_gmt":"2024-03-26T04:19:21","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=60879"},"modified":"2024-03-28T09:51:58","modified_gmt":"2024-03-28T04:21:58","slug":"jetpack-compose-managing-state-of-ui","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/jetpack-compose-managing-state-of-ui\/","title":{"rendered":"Jetpack Compose: Managing state of UI"},"content":{"rendered":"<p id=\"e2c6\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\">In Jetpack compose state determine what is shown on UI. It is a value that changes over time. There are 2 ways to maintain state.<\/p>\n<p id=\"a336\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\"><strong class=\"li fs\">Stateless composable<\/strong>: Stateless composable does not have any state or rely on parent state. This kind of composable does not require re- composition of UI. It is used to display static UI.<\/p>\n<p id=\"90a9\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\"><strong class=\"li fs\">Stateful composable<\/strong>: These kind of composable maintain their own state. it defines the internal state &amp; controls it. Jetpack compose has a reactive approach for storing state in a variable, we need to use MutableStateOf or observable like LiveData, Flow, etc. for the same. When the state change, the composable recompose itself, update the new ui with the new state.<\/p>\n<p id=\"de7b\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\">Let us understand state using counter app, which increase the count upon button click.<\/p>\n<p id=\"9c9f\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\">Let us create a method IncreaseCounter which is hard coded with 0<\/p>\n<blockquote>\n<pre class=\"me mf mg mh mi mj mk ml bo mm ba bj\"><span id=\"1ee1\" class=\"mn mo fr mk b bf mp mq l mr ms\" data-selectable-paragraph=\"\"><span class=\"hljs-selector-tag\">ComposeStateDemoTheme<\/span> {\r\n    <span class=\"hljs-selector-tag\">Column<\/span>(\r\n        modifier = Modifier.<span class=\"hljs-built_in\">fillMaxSize<\/span>(),\r\n        verticalArrangement = Arrangement.Center,\r\n        horizontalAlignment = Alignment.CenterHorizontally\r\n    ) {\r\n        <span class=\"hljs-selector-tag\">IncreaseCounter<\/span>(<span class=\"hljs-number\">0<\/span>)\r\n    }\r\n}<\/span><\/pre>\n<pre class=\"mt mj mk ml bo mm ba bj\"><span id=\"ab71\" class=\"mn mo fr mk b bf mp mq l mr ms\" data-selectable-paragraph=\"\"><span class=\"hljs-meta\">@Composable<\/span>\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-title\">IncreaseCounter<\/span><span class=\"hljs-params\">(count: <span class=\"hljs-type\">Int<\/span>)<\/span><\/span> {\r\n    <span class=\"hljs-keyword\">var<\/span> currentCount = <span class=\"hljs-number\">0<\/span>;\r\n    Column(\r\n        horizontalAlignment = Alignment.CenterHorizontally\r\n    ) {\r\n        Text(\r\n            <span class=\"hljs-string\">\"Count is : <span class=\"hljs-variable\">$currentCount<\/span>\"<\/span>,\r\n            style = MaterialTheme.typography.bodyLarge,\r\n            modifier = Modifier.padding(<span class=\"hljs-number\">5.<\/span>dp)\r\n        )\r\n        Button(\r\n            onClick = {\r\n                currentCount = count + <span class=\"hljs-number\">1<\/span>\r\n            },\r\n\r\n            contentPadding = PaddingValues(<span class=\"hljs-number\">16.<\/span>dp),\r\n            colors = ButtonDefaults.textButtonColors(\r\n                containerColor = Color.LightGray,\r\n                contentColor = Color.Black\r\n            )\r\n        ) {\r\n            Text(<span class=\"hljs-string\">\"Counter Increment\"<\/span>)\r\n        }\r\n    }\r\n\r\n}<\/span><\/pre>\n<\/blockquote>\n<figure class=\"me mf mg mh mi mx mu mv paragraph-image\">\n<div class=\"mu mv mw\"><img decoding=\"async\" loading=\"lazy\" class=\"bg ko my c\" role=\"presentation\" src=\"https:\/\/miro.medium.com\/v2\/resize:fit:540\/1*jHPlHYaqsdM-TIVAsI_ZiA.gif\" alt=\"\" width=\"270\" height=\"600\" \/><\/div>\n<\/figure>\n<p id=\"bd09\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\">When we run the app and click on increment button, notice that nothing is happening, that is because compose does not redraw when the state change until recomposes of composable method.<\/p>\n<p id=\"dc71\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\">This can be achieved using:<\/p>\n<p id=\"3156\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\"><strong class=\"li fs\">MutableStateOf: <\/strong>To indicate to compose that should track an object\u2019 state, the state needs to be of type State(immutable) or MutableState (mutable).<\/p>\n<blockquote>\n<pre class=\"me mf mg mh mi mj mk ml bo mm ba bj\"><span id=\"c1f9\" class=\"mn mo fr mk b bf mp mq l mr ms\" data-selectable-paragraph=\"\">ComposeStateDemoTheme {\r\n    Column(\r\n        modifier = Modifier.fillMaxSize(),\r\n        verticalArrangement = Arrangement.Center,\r\n        horizontalAlignment = Alignment.CenterHorizontally\r\n    ) {\r\n        <span class=\"hljs-keyword\">val<\/span> count = mutableStateOf(<span class=\"hljs-number\">0<\/span>)\r\n        IncreaseCounter(count)\r\n    }\r\n}<\/span><\/pre>\n<\/blockquote>\n<figure class=\"me mf mg mh mi mx mu mv paragraph-image\">\n<div class=\"mu mv mw\"><img decoding=\"async\" loading=\"lazy\" class=\"bg ko my c\" role=\"presentation\" src=\"https:\/\/miro.medium.com\/v2\/resize:fit:540\/1*ST2RvTUDKG4j5MmqLOJPaA.gif\" alt=\"\" width=\"270\" height=\"600\" \/><\/div>\n<\/figure>\n<p id=\"2862\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\">Above as you can see, <strong class=\"li fs\">MutableStateOf<\/strong> does the work but it is not the best way, because in jetpack compose every composable function recomposes independently so it can give unexpected if we use the same variable with multiple composable methods.<\/p>\n<p id=\"c46b\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\"><strong class=\"li fs\">remember<\/strong> <strong class=\"li fs\">API<\/strong>: To instruct Compose to retain and reuse its value during recompositions, you need to declare it with the remember API. It is used as a guard against the recomposition to avoid the state being reset.<\/p>\n<blockquote>\n<pre class=\"me mf mg mh mi mj mk ml bo mm ba bj\"><span id=\"ad48\" class=\"mn mo fr mk b bf mp mq l mr ms\" data-selectable-paragraph=\"\">ComposeStateDemoTheme {\r\n    Column(\r\n        modifier = Modifier.fillMaxSize(),\r\n        verticalArrangement = Arrangement.Center,\r\n        horizontalAlignment = Alignment.CenterHorizontally\r\n    ) {\r\n        <span class=\"hljs-keyword\">val<\/span> count = remember {\r\n            mutableStateOf(<span class=\"hljs-number\">0<\/span>)\r\n        }\r\n        IncreaseCounter(count)\r\n    }\r\n}<\/span><\/pre>\n<\/blockquote>\n<p id=\"2484\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\">The above code won\u2019t work on rotation of device i.e configuration changes etc. this can be avoided by using <strong class=\"li fs\">rememberSavable<\/strong> API.<\/p>\n<p id=\"0ba7\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\"><strong class=\"li fs\">rememberSavable API<\/strong>: It is used to save values that you need if Android OS destroys and recreates the activity.<\/p>\n<blockquote>\n<pre class=\"me mf mg mh mi mj mk ml bo mm ba bj\"><span id=\"dc9d\" class=\"mn mo fr mk b bf mp mq l mr ms\" data-selectable-paragraph=\"\">ComposeStateDemoTheme {\r\n        Column(\r\n            modifier = Modifier.fillMaxSize(),\r\n            verticalArrangement = Arrangement.Center,\r\n            horizontalAlignment = Alignment.CenterHorizontally\r\n        ) {\r\n            <span class=\"hljs-keyword\">val<\/span> count <span class=\"hljs-keyword\">by<\/span> rememberSaveable { mutableStateOf(<span class=\"hljs-number\">0<\/span>) }\r\n            IncreaseCounter(count)\r\n        }\r\n    }\r\n}<\/span><\/pre>\n<\/blockquote>\n<p id=\"9388\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\"><strong class=\"li fs\">Final Code<\/strong><\/p>\n<blockquote>\n<pre class=\"me mf mg mh mi mj mk ml bo mm ba bj\"><span id=\"64e7\" class=\"mn mo fr mk b bf mp mq l mr ms\" data-selectable-paragraph=\"\">ComposeStateDemoTheme {\r\n    Column(\r\n        modifier = Modifier.fillMaxSize(),\r\n        verticalArrangement = Arrangement.Center,\r\n        horizontalAlignment = Alignment.CenterHorizontally\r\n    ) {\r\n        <span class=\"hljs-keyword\">var<\/span> count <span class=\"hljs-keyword\">by<\/span> rememberSaveable { mutableStateOf(<span class=\"hljs-number\">0<\/span>) }\r\n        IncreaseCounter(currentCount = count) {\r\n            count = it + <span class=\"hljs-number\">1<\/span>;\r\n        }\r\n    }\r\n}<\/span><\/pre>\n<pre class=\"mt mj mk ml bo mm ba bj\"><span id=\"3ac7\" class=\"mn mo fr mk b bf mp mq l mr ms\" data-selectable-paragraph=\"\"><span class=\"hljs-meta\">@Composable<\/span>\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-title\">IncreaseCounter<\/span><span class=\"hljs-params\">(currentCount: <span class=\"hljs-type\">Int<\/span>, updateCount: (<span class=\"hljs-type\">Int<\/span>) -&gt; <span class=\"hljs-type\">Unit<\/span>)<\/span><\/span> {\r\n    Column(\r\n        horizontalAlignment = Alignment.CenterHorizontally\r\n    ) {\r\n        Text(\r\n            <span class=\"hljs-string\">\"Count is : <span class=\"hljs-subst\">${currentCount}<\/span>\"<\/span>,\r\n            style = MaterialTheme.typography.bodyLarge,\r\n            modifier = Modifier.padding(<span class=\"hljs-number\">5.<\/span>dp)\r\n        )\r\n        Button(\r\n            onClick = {\r\n                updateCount(currentCount)\r\n            },\r\n\r\n            contentPadding = PaddingValues(<span class=\"hljs-number\">16.<\/span>dp),\r\n            colors = ButtonDefaults.textButtonColors(\r\n                containerColor = Color.LightGray,\r\n                contentColor = Color.Black\r\n            )\r\n        ) {\r\n            Text(<span class=\"hljs-string\">\"Counter Increment\"<\/span>)\r\n        }\r\n    }\r\n\r\n}<\/span><\/pre>\n<\/blockquote>\n<p id=\"a985\" class=\"pw-post-body-paragraph lg lh fr li b lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md fk bj\" data-selectable-paragraph=\"\">Keep <strong class=\"li fs\">Learning<\/strong>! Keep <strong class=\"li fs\">Coding<\/strong>!<br \/>\nFollow us for more insights.<\/p>\n<div class=\"ap-custom-wrapper\"><\/div><!--ap-custom-wrapper-->","protected":false},"excerpt":{"rendered":"<p>In Jetpack compose state determine what is shown on UI. It is a value that changes over time. There are 2 ways to maintain state. Stateless composable: Stateless composable does not have any state or rely on parent state. This kind of composable does not require re- composition of UI. It is used to display [&hellip;]<\/p>\n","protected":false},"author":1560,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":14},"categories":[518],"tags":[4845,5637],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/60879"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1560"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=60879"}],"version-history":[{"count":2,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/60879\/revisions"}],"predecessor-version":[{"id":61016,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/60879\/revisions\/61016"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=60879"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=60879"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=60879"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}