Site icon C1CTech

State and State Hoisting in Android Jetpack Compose

&NewLine;<p>This article is about how to manage the state in Android Jetpack Compose&comma; state hoisting &lpar;<span class&equals;"devsite-heading" role&equals;"heading" aria-level&equals;"3">stateless composable<&sol;span>&rpar;&comma; and s<span class&equals;"devsite-heading" role&equals;"heading" aria-level&equals;"3">tateful versus stateless composable&period;<&sol;span><&sol;p> &NewLine; &NewLine; &NewLine; &NewLine;<h4><span style&equals;"color&colon; &num;000080&semi;"><strong>What is State in Jetpack Compose&quest;<&sol;strong><&sol;span><&sol;h4> &NewLine;<p>The state is an object that is connected&sol;subscribed to one or more widgets&comma; contains data&comma; and is eager to update the widgets from that data&period;<&sol;p> &NewLine;<p>If there’s any change happens in data&comma; it will update all its subscribed UI widgets&period; The values of the state are changed at runtime&period;<&sol;p> &NewLine;<p>The <strong class&equals;"kd jf"><span style&equals;"color&colon; &num;008000&semi;">&commat; composable function&lpar;s&rpar;<&sol;span> <span style&equals;"color&colon; &num;008000&semi;">recomposes<&sol;span> <&sol;strong>itself with the new data when the state&sol;object value is updated and doesn’t affect or update the whole UI&period;<&sol;p> &NewLine;<p><strong>In Jetpack Compose&comma; the composable are subscribed to a state&comma; and when the value of the state is updated then all the composable who are subscribed to it also update the value&period;<&sol;strong><&sol;p> &NewLine;<p>For example&comma; three texts are subscribed to a state&comma; and when the value of the state changes&comma; the text in these three would also be updated&period;<&sol;p> &NewLine;<p>With Jetpack compose&comma; we can preserve the state of view in major two ways&colon;<&sol;p> &NewLine;<ul> &NewLine;<li>Using <span style&equals;"color&colon; &num;008000&semi;"><strong>remember&lbrace;&rcub;<&sol;strong><&sol;span>&comma; a composable function that can store a single object in memory&comma; or by using <span style&equals;"color&colon; &num;008000&semi;"><strong>rememberSaveable&lbrace;&rcub;<&sol;strong><&sol;span>&comma; a composable function to restore your UI state after an activity or process is recreated &lpar;for example it happens when the screen is rotated in the Android application&rpar;&period; We can manage a simple state of view within a compose function itself&period;<&sol;li> &NewLine;<li>Using <strong><span style&equals;"color&colon; &num;008000&semi;">ViewModel<&sol;span><&sol;strong>&comma; a state holder to separate business logic from UI component&period; ViewModel has a longer lifecycle than the composition as they are lifecycle-aware components so ViewModel can preserve its state across configuration changes&period;<&sol;li> &NewLine;<&sol;ul> &NewLine;<h4 id&equals;"state-in-composables" role&equals;"presentation" data-text&equals;"State in composables"><span style&equals;"color&colon; &num;000080&semi;"><strong><span class&equals;"devsite-heading" role&equals;"heading" aria-level&equals;"2">remember Composable<&sol;span><&sol;strong><&sol;span><&sol;h4> &NewLine;<p>The <a href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;kotlin&sol;androidx&sol;compose&sol;runtime&sol;package-summary&num;remember&lpar;kotlin&period;Function0&rpar;"><span style&equals;"color&colon; &num;008000&semi;"><strong>remember&lbrace;&rcub;<&sol;strong><&sol;span><&sol;a> can be used to store both mutable and immutable objects&period; <&sol;p> &NewLine;<p>A value computed by remember&lbrace;&rcub; is stored in the Composition during <span style&equals;"color&colon; &num;0000ff&semi;"><strong>initial composition<&sol;strong><&sol;span>&comma; and the stored value is returned during recomposition&period;<&sol;p> &NewLine;<p>In each <span style&equals;"color&colon; &num;0000ff&semi;"><strong>recomposition<&sol;strong><&sol;span>&comma; remember&lpar;&rpar; returns the stored value so the composable can use it&period; Whenever the stored value has to change&comma; you can update it and remember&lpar;&rpar; will store it&period; The next time a recomposition occurs&comma; remember&lpar;&rpar; will provide the latest value&period;<&sol;p> &NewLine;<p><span style&equals;"color&colon; &num;000080&semi;"><strong>Key Term&colon; <&sol;strong><&sol;span><&sol;p> &NewLine;<ul> &NewLine;<li><span style&equals;"color&colon; &num;0000ff&semi;"><strong>Composition&colon;<&sol;strong><&sol;span> a description of the UI built by Jetpack Compose when it executes composables&period;<&sol;li> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">Initial composition&colon;<&sol;span><&sol;strong> creation of a Composition by running composables the first time&period;<&sol;li> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">Recomposition&colon;<&sol;span><&sol;strong> re-running composables to update the Composition when data changes&period;<br &sol;><br &sol;><&sol;li> &NewLine;<&sol;ul> &NewLine;<h5><span style&equals;"color&colon; &num;000080&semi;"><strong>Using mutableStateOf&lpar;&rpar;<&sol;strong><&sol;span><&sol;h5> &NewLine;<p>To create a state&comma; we need to use <strong><a href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;kotlin&sol;androidx&sol;compose&sol;runtime&sol;package-summary&num;mutableStateOf&lpar;kotlin&period;Any&comma;androidx&period;compose&period;runtime&period;SnapshotMutationPolicy&rpar;"><span style&equals;"color&colon; &num;0000ff&semi;">mutableStateOf&lpar;&rpar;<&sol;span><&sol;a> <&sol;strong>function&period; In this&comma; the state stores the value on execution&comma; and if any composable is subscribed to it&comma; the composable updates the value if there are any changes&period;<&sol;p> &NewLine;<p>There are three ways to declare a MutableState object in a composable&colon;<&sol;p> &NewLine;<p><span style&equals;"color&colon; &num;000000&semi;">1 &period; val mutableState &equals; remember &lbrace; mutableStateOf &lpar;default&rpar; &rcub;<&sol;span><&sol;p> &NewLine;<pre>&commat;Composable<br &sol;>fun HelloContent&lpar;&rpar; &lbrace;<br &sol;> Column&lpar;modifier &equals; Modifier&period;padding&lpar;16&period;dp&rpar;&rpar; &lbrace;<br &sol;><br &sol;><span style&equals;"color&colon; &num;008000&semi;"><strong> var name &equals; remember &lbrace; mutableStateOf&lpar;""&rpar; &rcub;<&sol;strong><&sol;span><br &sol;><br &sol;> if &lpar;name&period;value&period;isNotEmpty&lpar;&rpar;&rpar; &lbrace;<br &sol;> Text&lpar;<br &sol;> text &equals; "Hello&comma; &dollar;name&period;value&excl;"&comma;<br &sol;> modifier &equals; Modifier&period;padding&lpar;bottom &equals; 8&period;dp&rpar;&comma;<br &sol;> style &equals; MaterialTheme&period;typography&period;h5<br &sol;> &rpar;<br &sol;> &rcub;<br &sol;> OutlinedTextField&lpar;<br &sol;> value &equals; name&period;value&comma;<br &sol;> onValueChange &equals; &lbrace; name&period;value &equals; it &rcub;&comma;<br &sol;> label &equals; &lbrace; Text&lpar;"Name"&rpar; &rcub;<br &sol;> &rpar;<br &sol;> &rcub;<br &sol;>&rcub;<&sol;pre> &NewLine;<h6> <&sol;h6> &NewLine;<h6 id&equals;"7f74" class&equals;"ku kv ii bn kw kx ky kz la lb lc ld le jo lf jp lg jr lh js li ju lj jv lk ll gj"><span style&equals;"color&colon; &num;000080&semi;"><strong>Using Kotlin’s Delegated Property to access the State<&sol;strong><&sol;span><&sol;h6> &NewLine;<p><span style&equals;"color&colon; &num;000000&semi;">2 &period; var value by remember &lbrace; mutableStateOf&lpar;default&rpar; &rcub;<&sol;span><&sol;p> &NewLine;<p>In Kotlin&comma; there is a feature called Delegated Property&comma; which simply eliminates the need to access the value property every time&period;<&sol;p> &NewLine;<pre>&commat;Composable<br &sol;>fun HelloContent&lpar;&rpar; &lbrace;<br &sol;> Column&lpar;modifier &equals; Modifier&period;padding&lpar;16&period;dp&rpar;&rpar; &lbrace;<br &sol;><br &sol;><span style&equals;"color&colon; &num;000000&semi;"><strong> &sol;&sol;using kotlin's delegate property<&sol;strong><&sol;span><br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> var name by remember &lbrace; mutableStateOf&lpar;""&rpar; &rcub;<&sol;span><&sol;strong><br &sol;><br &sol;> if &lpar;name&period;isNotEmpty&lpar;&rpar;&rpar; &lbrace;<br &sol;> Text&lpar;<br &sol;> text &equals; "Hello&comma; &dollar;name&excl;"&comma;<br &sol;> modifier &equals; Modifier&period;padding&lpar;bottom &equals; 8&period;dp&rpar;&comma;<br &sol;> style &equals; MaterialTheme&period;typography&period;h5<br &sol;> &rpar;<br &sol;> &rcub;<br &sol;> OutlinedTextField&lpar;<br &sol;> value &equals; name&comma;<br &sol;> onValueChange &equals; &lbrace; name &equals; it &rcub;&comma;<br &sol;> label &equals; &lbrace; Text&lpar;"Name"&rpar; &rcub;<br &sol;> &rpar;<br &sol;> &rcub;<br &sol;>&rcub;<&sol;pre> &NewLine;<p><span style&equals;"color&colon; &num;000000&semi;">3&period; val &lpar;value&comma; setValue&rpar; &equals; remember &lbrace; mutableStateOf&lpar;default&rpar; &rcub;<&sol;span><&sol;p>&NewLine;<&excl;-- WP QUADS Content Ad Plugin v&period; 2&period;0&period;98&period;1 -->&NewLine;<div class&equals;"quads-location quads-ad2" id&equals;"quads-ad2" style&equals;"float&colon;none&semi;margin&colon;0px&semi;">&NewLine;&NewLine;<&sol;div>&NewLine; &NewLine;<pre>&commat;Composable<br &sol;>fun HelloContent&lpar;&rpar; &lbrace;<br &sol;> Column&lpar;modifier &equals; Modifier&period;padding&lpar;16&period;dp&rpar;&rpar; &lbrace;<br &sol;><br &sol;><strong><span style&equals;"color&colon; &num;008000&semi;"> val &lpar;name&comma; setName&rpar; &equals; remember &lbrace; mutableStateOf&lpar;""&rpar; &rcub;<&sol;span><&sol;strong><br &sol;><br &sol;> if &lpar;name&period;isNotEmpty&lpar;&rpar;&rpar; &lbrace;<br &sol;> Text&lpar;<br &sol;> text &equals; "Hello&comma; &dollar;name&excl;"&comma;<br &sol;> modifier &equals; Modifier&period;padding&lpar;bottom &equals; 8&period;dp&rpar;&comma;<br &sol;> style &equals; MaterialTheme&period;typography&period;h5<br &sol;> &rpar;<br &sol;> &rcub;<br &sol;> OutlinedTextField&lpar;<br &sol;> value &equals; name&comma;<br &sol;> onValueChange &equals; &lbrace; setName&lpar;it&rpar; &rcub;&comma;<br &sol;> label &equals; &lbrace; Text&lpar;"Name"&rpar; &rcub;<br &sol;> &rpar;<br &sol;> &rcub;<br &sol;>&rcub;<&sol;pre> &NewLine;<h6> <&sol;h6> &NewLine;<h6><span style&equals;"color&colon; &num;0000ff&semi;"><strong>Output&colon;<&sol;strong><&sol;span><&sol;h6> &NewLine;<p><img class&equals;"alignnone wp-image-3229" src&equals;"https&colon;&sol;&sol;c1ctech&period;com&sol;wp-content&sol;uploads&sol;2022&sol;05&sol;Screenshot&lowbar;2022-05-23-17-19-33-465&lowbar;com&period;c1ctech&period;jetpackcomposestateexp1-473x1024&period;png" alt&equals;"" width&equals;"294" height&equals;"636" &sol;><&sol;p> &NewLine;<p>&nbsp&semi;<&sol;p> &NewLine;<p><strong>Note&colon; If your device orientation gets changed&comma; the value will reset&period;<&sol;strong><&sol;p> &NewLine;<p>  <img class&equals;"alignnone wp-image-3233" src&equals;"https&colon;&sol;&sol;c1ctech&period;com&sol;wp-content&sol;uploads&sol;2022&sol;05&sol;Screenshot&lowbar;2022-05-24-12-17-26-382&lowbar;com&period;c1ctech&period;jetpackcomposestateexp1-1024x473&period;png" alt&equals;"" width&equals;"594" height&equals;"274" &sol;><&sol;p> &NewLine;<p>&nbsp&semi;<&sol;p> &NewLine;<p>If you want to keep the data even if the activity recreated&sol;orientation change happened&comma; use <strong><span style&equals;"color&colon; &num;0000ff&semi;">&&num;8220&semi;rememberSavable&&num;8221&semi;<&sol;span><&sol;strong>&period;<&sol;p> &NewLine;<h4><span style&equals;"color&colon; &num;000080&semi;"><strong>rememberSaveable C<&sol;strong><&sol;span><span style&equals;"color&colon; &num;000080&semi;"><strong><span class&equals;"devsite-heading" role&equals;"heading" aria-level&equals;"2">omposable<&sol;span><&sol;strong><&sol;span><&sol;h4> &NewLine;<p>Use <span style&equals;"color&colon; &num;0000ff&semi;"><strong><a style&equals;"color&colon; &num;0000ff&semi;" href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;kotlin&sol;androidx&sol;compose&sol;runtime&sol;saveable&sol;package-summary&num;rememberSaveable&lpar;kotlin&period;Array&comma;androidx&period;compose&period;runtime&period;saveable&period;Saver&comma;kotlin&period;String&comma;kotlin&period;Function0&rpar;">rememberSaveable&lbrace;&rcub;<&sol;a> <&sol;strong><&sol;span>to restore your UI state after an activity or process is recreated&period; RememberSaveable retains state across recompositions&period; In addition&comma; rememberSaveable also retains state across activity and process recreation&period;<&sol;p> &NewLine;<h6><strong><span style&equals;"color&colon; &num;0000ff&semi;">Example&colon;<&sol;span><&sol;strong><&sol;h6> &NewLine;<pre>&commat;Composable<br &sol;>fun HelloContent&lpar;&rpar; &lbrace;<br &sol;> Column&lpar;modifier &equals; Modifier&period;padding&lpar;16&period;dp&rpar;&rpar; &lbrace;<br &sol;><br &sol;> var name by <span style&equals;"color&colon; &num;008000&semi;"><strong>rememberSaveable<&sol;strong><&sol;span> &lbrace; mutableStateOf&lpar;""&rpar; &rcub;<br &sol;><br &sol;> println&lpar;"HelloContent&lpar;&rpar;&colon; &dollar;name"&rpar;<br &sol;><br &sol;> if &lpar;name&period;isNotEmpty&lpar;&rpar;&rpar; &lbrace;<br &sol;> Text&lpar;<br &sol;> text &equals; "Hello&comma; &dollar;name&excl;"&comma;<br &sol;> modifier &equals; Modifier&period;padding&lpar;bottom &equals; 8&period;dp&rpar;&comma;<br &sol;> style &equals; MaterialTheme&period;typography&period;h5<br &sol;> &rpar;<br &sol;> &rcub;<br &sol;> OutlinedTextField&lpar;<br &sol;> value &equals; name&comma;<br &sol;> onValueChange &equals; &lbrace; name &equals; it &rcub;&comma;<br &sol;> label &equals; &lbrace; Text&lpar;"Name"&rpar; &rcub;<br &sol;> &rpar;<br &sol;> &rcub;<br &sol;>&rcub;<&sol;pre> &NewLine;<h6><span style&equals;"color&colon; &num;0000ff&semi;"><strong>Output&colon;<&sol;strong><&sol;span><&sol;h6> &NewLine;<p><img class&equals;"alignnone wp-image-3235" src&equals;"https&colon;&sol;&sol;c1ctech&period;com&sol;wp-content&sol;uploads&sol;2022&sol;05&sol;Screenshot&lowbar;2022-05-24-12-14-34-869&lowbar;com&period;c1ctech&period;jetpackcomposestateexp1-473x1024&period;png" alt&equals;"" width&equals;"273" height&equals;"591" &sol;>    <img class&equals;"alignnone wp-image-3234" src&equals;"https&colon;&sol;&sol;c1ctech&period;com&sol;wp-content&sol;uploads&sol;2022&sol;05&sol;Screenshot&lowbar;2022-05-24-12-14-47-578&lowbar;com&period;c1ctech&period;jetpackcomposestateexp1-1024x473&period;png" alt&equals;"" width&equals;"604" height&equals;"279" &sol;><&sol;p> &NewLine;<p>&nbsp&semi;<&sol;p> &NewLine;<h4><span style&equals;"color&colon; &num;000080&semi;"><strong>State Hoisting<&sol;strong><&sol;span><&sol;h4> &NewLine;<p>State hoisting in Compose is a pattern of moving state to a composable&&num;8217&semi;s caller to make a composable stateless&period;<&sol;p> &NewLine;<p>The general pattern for state hoisting in Jetpack Compose is to replace the state variable with two parameters&colon;<&sol;p> &NewLine;<ul> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">value&colon; T&colon;<&sol;span> <&sol;strong>the current value to display<&sol;li> &NewLine;<li><strong><span style&equals;"color&colon; &num;0000ff&semi;">onValueChange&colon; &lpar;T&rpar; -&gt&semi; Unit&colon;<&sol;span><&sol;strong> an event that requests the value to change&comma; where T is the proposed new value<&sol;li> &NewLine;<&sol;ul> &NewLine;<p>Each composable can have many value parameters and many event callbacks&period;<&sol;p> &NewLine;<h6><strong><span style&equals;"color&colon; &num;0000ff&semi;">Example&colon;<&sol;span><&sol;strong><&sol;h6> &NewLine;<pre>&commat;Composable<br &sol;>fun HelloScreen&lpar;&rpar; &lbrace;<br &sol;> var name by rememberSaveable&lbrace; mutableStateOf&lpar;""&rpar; &rcub;<br &sol;><br &sol;> HelloContent&lpar;name &equals; name&comma; onNameChange &equals; &lbrace; name &equals; it &rcub;&rpar;<br &sol;>&rcub;<br &sol;><br &sol;>&commat;Composable<br &sol;>fun HelloContent&lpar;name&colon; String&comma; onNameChange&colon; &lpar;String&rpar; -&gt&semi; Unit&rpar; &lbrace;<br &sol;> Column&lpar;modifier &equals; Modifier&period;padding&lpar;16&period;dp&rpar;&rpar; &lbrace;<br &sol;> Text&lpar;<br &sol;> text &equals; "Hello&comma; &dollar;name"&comma;<br &sol;> modifier &equals; Modifier&period;padding&lpar;bottom &equals; 8&period;dp&rpar;&comma;<br &sol;> style &equals; MaterialTheme&period;typography&period;h5<br &sol;> &rpar;<br &sol;> OutlinedTextField&lpar;<br &sol;> value &equals; name&comma;<br &sol;> onValueChange &equals; onNameChange&comma;<br &sol;> label &equals; &lbrace; Text&lpar;"Name"&rpar; &rcub;<br &sol;> &rpar;<br &sol;> &rcub;<br &sol;>&rcub;<&sol;pre> &NewLine;<p>By hoisting the state out of <span style&equals;"color&colon; &num;008000&semi;"><strong>HelloContent<&sol;strong><&sol;span>&comma; it&&num;8217&semi;s easier to reason about the composable&comma; reuse it in different situations&comma; and test&period; <span style&equals;"color&colon; &num;008000&semi;"><strong>HelloContent<&sol;strong><&sol;span> is decoupled from how its state is stored&period; Decoupling means that if you modify or replace HelloScreen&comma; you don&&num;8217&semi;t have to change how HelloContent is implemented&period;<&sol;p> &NewLine;<h4><span style&equals;"color&colon; &num;000080&semi;"><strong>Stateful versus Stateless<&sol;strong><&sol;span><&sol;h4> &NewLine;<p>A composable that uses remember to store an object creates an internal state&comma; making the <span style&equals;"color&colon; &num;0000ff&semi;"><strong>composable stateful<&sol;strong><&sol;span>&period;<&sol;p> &NewLine;<p><span style&equals;"color&colon; &num;008000&semi;"><strong>HelloContent<&sol;strong><&sol;span> is an example of a stateful composable because it holds and modifies its name state internally&period; This can be useful in situations where a caller doesn&&num;8217&semi;t need to control the state and can use it without having to manage the state themselves&period; However&comma; composables with internal state tend to be less reusable and harder to test&period;<&sol;p> &NewLine;<p>A <strong><span style&equals;"color&colon; &num;0000ff&semi;">stateless composable<&sol;span><&sol;strong> is a composable that doesn&&num;8217&semi;t hold any state&period; An easy way to achieve stateless is by using <span style&equals;"color&colon; &num;008000&semi;"><strong>state hoisting<&sol;strong><&sol;span>&period;<&sol;p> &NewLine;<p>The stateful version is convenient for callers that don&&num;8217&semi;t care about the state&comma; and the stateless version is necessary for callers that need to control or hoist the state&period;<&sol;p> &NewLine;<p>&nbsp&semi;<&sol;p> &NewLine;&NewLine;

Exit mobile version