Введение в состояние компонентов

Последнее обновление: 03.04.2024

Jetpack Compose применяет декларативный подход для создания интерфейса, поэтому единственный способ обновить визуальный компонент представляет повторный вызов функции этого компонента, в которую передаются новые значения. И чтобы упростить обновление компонентов и вообще визуального интерфейса Jetpack Compose предоставляет концепцию состояние или state. Состояние представляет некоторое значение, которое хранится в приложении и которое в процессе его работы может изменяться.

Когда значение состояния изменяется, происходит рекомпозиция (recomposition) или обновление пользовательского интерфейса. Перекомпоновка всего пользовательского интерфейса каждый раз при изменении значения состояния была бы крайне неэффективным подходом к рендерингу и обновлению пользовательского интерфейса. Compose позволяет избежать этих накладных расходов, используя метод, называемый интеллектуальной рекомпозицией, который включает в себя перекомпоновку только тех компонентов, на которые непосредственно влияет изменение состояния. Как только Compose обнаруживает изменение состояния, он перекомпоновывает любые компоненты, на которые повлияло изменение состояния. Перекомпоновка просто означает, что функция компонента вызывается снова, и ей передается новое значение состояния.

MutableState

Измененяемое состояние в Jetpack Compose представлено объектом интерфейса MutableState<T>, который имеет следующее определение:

interface MutableState<T> : State<T> {
    override var value: T
}

Объект этого интерфейса хранит значение, которое будет изменяться, в виде переменной value. Причем данное значение может представлять любой тип.

Объект MutableState<T> интегрирован со средой выполнения Compose и позволяет отслеживать изменения хранимого в нем значения. Любые изменения этого значения приведут к обоновлению (или рекомпозиции) любого компонента, который использует данное значение.

Для создания объекта MutableState<T> Jetpack Compose предоставляет функцию mutableStateOf():

val mutableState = mutableStateOf(значение)

В функцию mutableStateOf() в качестве параметра передается отслеживаемое значение. Возвращаемый из функции объект MutableState позволяет связать отслеживаемое значение с компонентом.

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val message = mutableStateOf("Hello METANIT.COM")
            Text(text = message.value, fontSize = 25.sp)
        }
    }
}

Здесь в функцию mutableStateOf() передается строка, то есть объект String, поэтому возвращаемый функцией объект будет представлять тип MutableState<String>. С помощью свойства value можно получить отслеживаемое значение: message.value. В данном случае это значение передается в компонент Text для отображения.

Однако просто определение состояния - это еще не все. B вполне возможно, что Android Studio даже не сможет скомпилировать выше приведенный код. Потому что нам нужен еще ожин элемент - функция remember. Эта функция применяется для сохранения некоторого объекта в памяти. Она может хранить как изменяемые (mutable), так и неизменяемые (immutable) объекты. Причем данные объекты сохраняются во время начального построения интерфейса (то что называется initial composition) и продолжают храняться во время обновлений интерфейса (рекомпозиции).

Есть несколько способов применения функции remember в сочетании с функцией mutableStateOf. Самый распространенный:

val mutableState = remember { mutableStateOf(значение) }

Изменим пример выше с изменением текста, применив функцию remember:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val message = remember{mutableStateOf("Hello METANIT.COM")}
            Text(text = message.value, fontSize = 25.sp)
        }
    }
}
MutableState и mutableStateOf в Kotlin и Jetpack Compose в Android

Обращаясь к свойству value также можно изменить отслеживаемое значение:

val mutableState = mutableStateOf("Hello METANIT.COM")
mutableState.value = "Hello World"

Теперь посмотрим, как динамически изменять это состояние. Компонент Text позволяет применить модификатор clickable, который обрабатывает нажатия на компонент. Применим этот модификатор для динамического изменения текста в компоненте Text по нажатию на него:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.material3.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val message = remember{mutableStateOf("Hello METANIT.COM")}
            Text(
                text = message.value,
                fontSize = 25.sp,
                modifier = Modifier.clickable( onClick = { message.value = "Hello Work!" })
            )
        }
    }
}

Здесь в модификаторе clickable параметру onClick передается обаботчик нажатия, который изменяет отслеживаемое значение. То есть мы ожидаем, что по нажатию на текст он изменится с "Hello METANIT.COM" на "Hello Work!".

Функции mutableStateOf и remember в Kotlin и Jetpack Compose в Android

Стоит отметить, что есть еще два способа использования функции remember:

var value by remember { mutableStateOf(значение) }

В этом случае применятся делегат by, для работы с которым необходимо импортировать следующие функции:

import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

Применение второго варианта:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.material3.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            var value by remember{mutableStateOf("Hello METANIT.COM")}

            Text(
                text = value,
                fontSize = 28.sp,
                modifier = Modifier.clickable( onClick = { value = "Hello Word"})
            )
        }
    }
}

И последний третий вариант выглядит следующим образом:

val (value, setValue) = remember { mutableStateOf(значение) }

В этом случае возвращается собственно отслеживаемое значение (value) и функция обработки изменения этого значения (setValue). Для примера применим этот вариант:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.unit.sp
import androidx.compose.foundation.clickable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val (value, setValue) = remember{mutableStateOf("Hello METANIT.COM")}

            Text(
                text = value,
                fontSize = 28.sp,
                modifier = Modifier.clickable( onClick = { setValue("Hello Word")})
            )
        }
    }
}

Теперь мы берем из MutableState отдельно само отслеживаемое значение в виде переменной value и отдельно обаботчик обновления этого значения в виде функции setValue. Поскольку отслеживаемое значение представляет объект String, то функция setValue() также принимает объект String. И в данном случае мы передаем подобный объект: setValue("Hello Word"). А обаботчик сам установит данное значение.

Сохранение состояния при изменении ориентации

Выше мы рассмотрели сохранение состояния, его получение и изменение. Однако даже если мы изменим состояние, при изменении ориентации мобильного устройства (например, при переходе от портретного режима к алюбомному) наше состояние пропадет:

mutableStateOf и remember в Kotlin и Jetpack Compose в Android

То же самое касается и других конфигурационныхт изменений, например, измненения системных настроек. Подобные изменения вызывают не просто рекомпозицию отдельных компонентов, а уничтожение и пересоздание всего класса MainActivity. В итоге вновь созданный объект MainActivity не понмнит никаких изменений состояния.

Для сохранения состояния между поворотами экрана и другими подобными системными изменениями конфигурации применяется обертка над функцией remember - функцию rememberSaveable, которая сохраняет данные в объект Bundle. Правда, не все объекты можно сохранить, а только данные примитивных типов, либо классов, которые реализуют интерфейс Parcelable. Например, изменим предыдущий пример применив функцию rememberSaveable:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.material3.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            var value by rememberSaveable{mutableStateOf("Hello METANIT.COM")}

            Text(
                text = value,
                fontSize = 28.sp,
                modifier = Modifier.clickable( onClick = { value = "Hello Work!"})
            )
        }
    }
}
mutableStateOf и rrememberSaveable в Kotlin и Jetpack Compose в Android
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850