Каждый раз, когда я перезапускаю приложение, значения, сохраненные в хранилище данных настроек, сбрасываются.
В частности, я пытаюсь сохранить, выбрал ли пользователь светлый или темный режим для своей предпочтительной фоновой темы. Однако он не сохраняется при перезапуске приложения.
Я использую логическое значение для определения фоновой темы, а затем сохраняю ее с помощью хранилища данных настроек.
Вот класс хранилища данных, который используется для доступа к значению:
import android.content.Context
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
private val Context.dataStore by preferencesDataStore("ThemeDatastore")
class ThemeDatastore(private val context: Context) {
val themeKey = booleanPreferencesKey("Theme")
fun loadTheme(key: Preferences.Key<Boolean>): Flow<Boolean> =
context.dataStore.data.map { preferences ->
preferences[key] ?: false
}
suspend fun saveTheme(key: Preferences.Key<Boolean>, data: Boolean) {
context.dataStore.edit { preferences ->
preferences[key] = data
}
}
}
Ниже приведен код Compose в основном действии.
Это экземпляр ThemeDatastore
. В поле параметра контекста указан текущий локальный контекст:
val themeDatastore = ThemeDatastore(LocalContext.current)
Вот переменная, которая извлекает предпочтительную фоновую тему. Изначально установлено значение false:
val savedTheme = themeDatastore.loadTheme(key = themeDatastore.themeKey).collectAsState(initial = false)
Вот логическая переменная, определяющая фоновую тему. Если false, активен светлый режим, если true, активен темный режим. Изначально установлено значение false:
var isDarkModeActive by remember { mutableStateOf(false) }
Вот функция, которая вызывает функцию из ThemeDatastore
, сохраняющую предпочтительную фоновую тему:
fun saveTheme(){
CoroutineScope(Dispatchers.IO).launch {
themeDatastore.saveTheme(themeDatastore.themeKey, isDarkModeActive)
}
}
Вот макет приложения. Это поле, занимающее весь экран. Цвет фона становится темно-серым, если isDarkModeActive
и saveTheme.value
оба равны true:
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.background(
color = animateColorAsState(
targetValue = if (isDarkModeActive && savedTheme.value)
Color.DarkGray else Color.White
).value
)
.fillMaxSize(),
) {
Button(onClick = {
isDarkModeActive = !isDarkModeActive
saveTheme()
}) {
Text(text = "Toggle Theme")
}
}
В центре экрана находится кнопка. При нажатии кнопки isDarkModeActive
переключается между true и false и запускается функция saveTheme.
Я попытался установить для начального значения переменной savedTheme
значение true. Это не сработало.
Хорошо, я удалил упоминания об Android Studio.
DataStore работает отлично, просто вы явно устанавливаете для темного режима значение false при загрузке компонуемого объекта:
var isDarkModeActive by remember { mutableStateOf(false) }
Значение DataStore не имеет значения, isDarkModeActive
всегда будет ложным при перезапуске приложения.
У вас должен быть только один источник достоверности для любых данных. В данном случае это означает, что вам следует удалить одно из двух значений, указывающих, включен ли темный режим:
val themeDatastore = ThemeDatastore(LocalContext.current)
val isDarkModeActive by themeDatastore.loadTheme(key = themeDatastore.themeKey)
.collectAsStateWithLifecycle(false)
val scope = rememberCoroutineScope()
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.background(
color = animateColorAsState(
targetValue = if (isDarkModeActive)
Color.DarkGray else Color.White,
).value,
)
.fillMaxSize(),
) {
Button(onClick = {
scope.launch {
themeDatastore.saveTheme(themeDatastore.themeKey, !isDarkModeActive)
}
}) {
Text(text = "Toggle Theme")
}
}
Хотя нет необходимости исправлять эту проблему, я внес два дополнительных изменения:
collectAsState
на collectAsStateWithLifecycle
из зависимости gradle androidx.lifecycle:lifecycle-runtime-compose
, чтобы сэкономить ресурсы при изменении жизненного цикла.saveTheme
, которая создавала неуправляемый CoroutineScope
. Вместо этого вам следует получить управляемую область с помощью rememberCoroutineScope()
.Теперь это должно работать так, как задумано.
И последнее: ключ, который вы передаете loadTheme
и saveTheme
, должен быть личным для ThemeDatastore
и напрямую использоваться функциями, а не передаваться в качестве параметра. Никогда не возникнет ситуация, когда вам захочется использовать что-то другое, кроме themeDatastore.themeKey
.
Это сработало. Спасибо, добрый сэр. Однако есть еще одна проблема. Когда приложение запустится, оно запустится в светлом режиме, а затем сразу же перейдет в темный режим. Можно ли это исправить?
Это определяется начальным значением, передаваемым в collectAsStateWithLifecycle
. Это значение будет использоваться до тех пор, пока DataStore не предоставит свое первое значение. Вы можете установить для него значение true
, если хотите (тогда он всегда будет запускаться в темном режиме, пока не станут доступны настройки из DataStore), вы даже можете установить его на ноль и, далее, решить, что вы хотите делать, когда информация темнеет. (false) или световой индикатор (true) недоступен. Это больше о том, чего вы хотите.
Если мой ответ помог решить вашу проблему, вы можете проголосовать за него и принять его, нажав галочку слева. Вы также можете просмотреть свои старые вопросы и выбрать решение, которое вам помогло. Это также поможет будущим посетителям сайта, которые наткнутся на ваш вопрос, определить качество ответов. Кроме того, это дает вам и автору ответа, который вы принимаете, несколько очков репутации.
Просто чтобы убедиться, это происходит только при перезапуске приложения в Android Studio? При перезапуске приложения с помощью самого устройства все нормально? Если нет, то отредактируйте вопрос и удалите явное упоминание Android Studio в этом контексте.