Skip to main content

Jetpack Compose with remember and mutableStateOf

 Jetpack Compose is a modern declarative UI Toolkit . In jetpack's declarative approach widgets are stateless and does not expose getter or setter function . So we cannot update UI with button.setText(String) or img.setImageBitmap().... 

In Compose we build UI by defining set of Composable function. Composable function take in data and emit UI elements. So in Compose  only way to  update the UI is by calling the same Composable function with new Arguments. This Argument represents UI State. State in an app is any value that changes over time , this includes simple class variable to Room Database. Any time a State is updated we need to call the Composable with new State to update the UI. This is called ReComposition

This Demo Jetpack Compose app will help you understand the basics of Jetpack Compose.

Screenshots of this App

 
This is our MainActivity
package com.arun.androidtutsforu.democompose
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.arun.androidtutsforu.democompose.ui.theme.DemoComposeTheme
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            DemoComposeTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    CalculateScreen()
                }
            }
        }
    }
}
@Composable
fun CalculateScreen(){
    var firstNum by remember { mutableStateOf("")}
    var secondNum by remember { mutableStateOf("")}
    val num1 = firstNum.toIntOrNull()?:0
    val num2 = secondNum.toIntOrNull()?:0
    val sum = num1+num2
    Column(
        modifier = Modifier.padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
        ) {
        Text(
            text = "JetPack Compose Demo",
            fontWeight = FontWeight.Bold,
            fontSize = 20.sp,
            color = Color.Blue
        )
        Spacer(modifier = Modifier.height(32.dp))
        TextField(
            value =firstNum ,
            onValueChange ={firstNum = it} ,
            label = { Text(text = "Enter First Num")}
        )
        Spacer(modifier = Modifier.height(16.dp))
        TextField(
            value = secondNum,
            onValueChange = {secondNum=it},
            label = { Text(text = "Enter Second Num")}
        )
        Spacer(modifier = Modifier.height(16.dp))
        Text(
            text = "The sum is $sum",
            fontWeight = FontWeight.Bold,
            fontSize = 20.sp
        )
    }
}
 @Composable
fun CalculateScreen(){
   ....
   ....
   }
This is our Composable function . In Compose we build UI by defining set of Composable function
Column(modifier = Modifier.padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
       ) {
        ....
        ....
        }
we use Column to place elements vertically on the screen
var firstNum by remember { mutableStateOf("")}
var secondNum by remember { mutableStateOf("")}

mutableStateOf is an Observable type integrated with android runtime.So when we define any state  as mutableStateOf , any changes to that state will schedule recomposition of every composable function that reads that state.

Composable uses remember API to store an object in memory . Stored value is returned during recomoposition. We use remember and mutableStateof to update the UI.

val value = remember{mutableStateof(default)
val value by remember{muableStateof(default)

when we use by delegates we use the following imports

import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
our var firstNum,secondNum are defined as mutableStateOf with default value " ". So when its value changes in 
onValueChange={firstNum=it}.
It will schedule recomposition and updates our UI.
TextField(
            value =firstNum ,
            onValueChange ={firstNum = it} ,
            label = { Text(text = "Enter First Num")}
        )
        ...
        TextField(
            value = secondNum,
            onValueChange = {secondNum=it},
            label = { Text(text = "Enter Second Num")}
        )
remember helps us retain the State across recomposition . But when configuration changes happens (rotation of the device ) and on process death whole activity  restarts and all the state will be lost. So We must use rememberSeaveble instead of remember , rememberSeaveble will survive configuration changes and process death . rememberSaveable automatically saves any value that can be saved in a Bundle. For other values we can pass a custom saver objects
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            DemoComposeTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    CalculateScreen()
                }
           }
        }
    }
}
@Composable
fun CalculateScreen(){
    var firstNum by rememberSaveable{ mutableStateOf("")}
    var secondNum by rememberSaveable { mutableStateOf("")}
    val num1 = firstNum.toIntOrNull()?:0
    val num2 = secondNum.toIntOrNull()?:0
    val sum = num1+num2
    Column(
        modifier = Modifier.padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
        ) {
        Text(
            text = "JetPack Compose Demo",
            fontWeight = FontWeight.Bold,
            fontSize = 20.sp,
            color = Color.Blue
        )
        Spacer(modifier = Modifier.height(32.dp))
        TextField(
            value =firstNum ,
            onValueChange ={firstNum = it} ,
            label = { Text(text = "Enter First Num")}
        )
        Spacer(modifier = Modifier.height(16.dp))
        TextField(
            value = secondNum,
            onValueChange = {secondNum=it},
            label = { Text(text = "Enter Second Num")}
        )
        Spacer(modifier = Modifier.height(16.dp))
        Text(
            text = "The sum is $sum",
            fontWeight = FontWeight.Bold,
            fontSize = 20.sp
        )
    }
}
You can Download full Source code of this App From my github



Comments

Popular posts

Simple Calculator in Android

You can view new updated simple calculator with ViemModel and LiveData in my new blog    https://androidtuts4u.blogspot.com/2021/10/simple-calculator-with-viewmodel-and.html To create a calculator first  we need to create the layout of the calculator. Layout  is created  using XML file given below <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent" >  <EditText     android:id="@+id/result_id"       android:layout_width="fill_parent"     android:layout_height="120dp"   />  <Button    android:id="@+id/Btn7_id"      android:layout_width="70dp"    android:layout_height="60dp"    android:layout_below="@id/result_id"   ...

ViewModel with Jetpack Compose

  Compose uses remember API to store object in memory. Stored value is returned during recomposition . remember helps us retain data across recompostion , but when configuration changes happen all stored values are lost . One way to overcome this is to use rememberSaveable . rememberSaveable saves any value that can be saved in a Bundle , so it will survive configuration changes.  But when we are using lot of data , for example a list we can cannot use a rememberSavble beacuse there is limit on amount of data that can be stored in Bundle . So we use ViweModel . ViewModel provide the ui state and access to the business logic located in other layers of the app. It also survives configuration changes. ViewModel handles events coming from the UI or other layers of the app and updates the state holder based on the events. We need to add the following dependency in our app level build.gradle to use ViewModel implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1" F...

Enabling Sign-in APi in Google Developer console

We need to enable Sign-in Api for our application in google developers console to use google sign-in  in our application. 1 . first we need to create a project in google developers console     visit google developers  console        https://console.developers.google.com/project 2 .  Click on create project button you will see the below screen     3 .  Enter project name and click CREATE . Then we are directed to project home page  which will look like this 4 .  Next we need to add Google API to our project. click on library on left menu and search for google api 5 .  Configure  OAuth consent screen , click on 'OAuth consent screen '  6  .  Enter Application name and email id everything else is optional  and click save   7  . Configure Credentials        Google uses this to ensure that your application is not fake applicatio...