State Management - devrath/urban-octo-jetpack-compose GitHub Wiki

What is state management in jetpack compose

  • Concept of the state is the important part of the compose concept.
  • Based on the state the UI is being built.
Contents
State and recomposition
Recomposition in detail
State hoisting
Using the state in the view-model

State and recomposition

  • Recomposition is basically the process of redrawing the screen and basically reloading the composable.
  • To trigger a recomposition, basically we need to have a state for the composable.
  • A state in an application is any value that can change over time.
  • In JetpackCompose, We need to implement state as a standalone component for a composable.
  • There is the unidirectional flow: Event -----> Update State -----> Display State
  • Advantages of State
    • Since there is unidirectional flow from state ---> UI and UI ---> state, Individual components are easily testable.
    • Since the state is updated in one place, there is less possibility of the cause of bugs.
    • All the states are immediately reflected in UI by the observable state holders.

Recomposition in detail

  • Some important terminologies here are
    • Composition

      • Compose means drawing something, Say a function annotated with compose draws a UI.
      • Now a compose function is nested with multiple nested compose functions, Now it follows a similar tree structure drawing principle
    • ReComposition

      • Now coming to recomposition, we need to understand how it works.
      • Would it redraw all the UI every time, If we are re-drawing every time, it will be an expensive operation sure.
      • UI update is handled by recomposition, but we need a way to tell for recomposition.
      • We control the composition by using the state variable. The state variable is a wrapper around a normal variable.
      • We usually define the state variable in three ways
        val mutableState = mutableStateOf(default)       // -- > WAY-1
        val (value, setValue) = mutableStateOf(default)  // -- > WAY-2
        var value by mutableStateOf(default)             // -- > WAY-3
        
      • The state variable is like a remote control used to control the drawing of a view, also can say re-drawing of a view. We don't need to call the function again but we just set the state variables.
      • Business logic needs to worry about only updating the state variables and the UI will take care of redrawing from its own. We don't access the object by its ID and stuff like that.
      • Say when there are 5 layers of composable defined as a tree hierarchy. Each layer has a state and if you update just of the states, all other states are not affected and just that particular state layer is recomposed.
    • Remember

      • State variable lies outside the composable function but if we use remember we can use the `state variable inside the composable function also.
      • Without the remember function if we use the state function, When the UI is re-drawn the variable is re-set. But by using the remember block we can ask to make the state retrieve the previous state.
      • Encapsulating the state variable within a composable function is done using something called remember
      • Using the remember we can ask them to remember function to retrieve the previous state when recomposed instead of creating a new state. and hence making it persist within the recomposable function.
      • Best way is to supply the state variable externally and instead of adding to the compose function so that there is the separation of business logic and UI logic and the state restoration is handled in a better way.

State hoisting

  • We understood that we can have the state of the composable globally, Then we moved the state into the leaf composable and showed to handle it.
  • But this results in giving multiple composable to manage the state, which is a bad practice.
  • We need to have a single source of truth, Meaning the parent most root composable can have the state of all the composable in its children hierarchy.
  • Also we need to keep in main the state and updating to the states must be done from a single point of reference

Using the state in the view-model

  • View model is a class responsible for preparing and managing the state of UI for fragments and activities.
  • View model has the relationship with the view in order to prepare the data to be displayed in the presentation layer.
  • The view binds to the view model and expects something to be displayed. Something can be the input data.
  • The view model also contains the UI-state, This state is responsible for preparing and managing the UI. The UI-state is basically what the UI will display.
  • Now we can have the logic for displaying and managing the widgets in view model instead of the view.
  • UI-state will acts as a single source of truth for the view.
  • Now the UI-state is present in the view model, Instead of view asking for the new states every time for the view model, There is a better approach of binding the view object to a live data state so that when the live data is updated the bound UI is also updated.
  • Also the live data is life cycle aware. Basically using the live data one can bind the view to the view model and expect to be updated when the live data changes.