У меня есть приложение для Android, которое хранит простые значения с помощью Preferences DataStore. У меня нет экземпляров Proto Datastore.
Проблема в том, что мое приложение совершенно случайно начинает давать сбой при запуске, обычно после слишком много раз очистки пользовательских данных. Я понятия не имею, почему это происходит, поскольку, похоже, оно срабатывает даже без вмешательства в мой репозиторий DataStore.
Это MainActivity (единственное действие):
...
data class AppPreferences(
val welcomeScreen: Boolean,
val name: String,
val listId: String,
val listPassword: String,
val lastChanged: Long,
)
class PreferencesRepository(
private val preferencesDatastore: DataStore
,
context: Context
) {
private object PreferencesKeys {
val WELCOME_SCREEN = booleanPreferencesKey("welcome_screen")
val USER_NAME = stringPreferencesKey("user_name")
val LIST_ID = stringPreferencesKey("list_id")
val LIST_PASSWORD = stringPreferencesKey("list_password")
val LAST_CHANGED = longPreferencesKey("last_changed")
val UI_STATE = intPreferencesKey("ui_state")
}
val preferencesFlow: Flow = preferencesDatastore.data.map { preferences ->
val welcomeScreen = preferences[PreferencesKeys.WELCOME_SCREEN] ?: true
val name = preferences[PreferencesKeys.USER_NAME] ?: ""
val listId = preferences[PreferencesKeys.LIST_ID] ?: ""
val listPassword = preferences[PreferencesKeys.LIST_PASSWORD] ?: ""
val lastChanged = preferences[PreferencesKeys.LAST_CHANGED] ?: -1
AppPreferences(welcomeScreen, name, listId, listPassword, lastChanged)
}
suspend fun updateUiState(state: UiState) {
preferencesDatastore.edit{ it[PreferencesKeys.UI_STATE] = state.ordinal}
}
val uiState: Flow = preferencesDatastore.data.map {
val e = it[PreferencesKeys.UI_STATE] ?: UiState.LOADED
enumValues().first { it.ordinal == e }
}
suspend fun updateNameAndListId(name: String, listId: String) {
preferencesDatastore.edit { preferences ->
preferences[PreferencesKeys.USER_NAME] = name
preferences[PreferencesKeys.LIST_ID] = listId
}
}
suspend fun updateUserPrefs(name: String, listId: String, listPassword: String) {
preferencesDatastore.edit {preferences ->
preferences[PreferencesKeys.WELCOME_SCREEN] = false
preferences[PreferencesKeys.USER_NAME] = name
preferences[PreferencesKeys.LIST_ID] = listId
preferences[PreferencesKeys.LIST_PASSWORD] = listPassword
}
}
}
И, наконец, моя трассировка стека:
java.util.NoSuchElementException: Массив не содержит элементов, соответствующих предикату. в com.example.comprinhas.data.PreferencesRepository$special$$inlined$map$2$2.emit(Emitters.kt:227) в kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke(SafeCollector.kt:15) в kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke(SafeCollector.kt:15) в kotlinx.coroutines.flow.internal.SafeCollector.emit(SafeCollector.kt:87) в kotlinx.coroutines.flow.internal. SafeCollector.emit(SafeCollector.kt:66) в androidx.datastore.core.SingleProcessDataStore$data$1$invokeSuspend$$inlined$map$1$2.emit(Collect.kt:137) в kotlinx.coroutines.flow.FlowKt__LimitKt$dropWhile$1 $1.emit(Limit.kt:40) в kotlinx.coroutines.flow.StateFlowImpl.collect(StateFlow.kt:396) в kotlinx.coroutines.flow.FlowKt__LimitKt$dropWhile$$inlined$unsafeFlow$1.collect(SafeCollector.common. kt:114) в androidx.datastore.core.SingleProcessDataStore$data$1$invokeSuspend$$inlined$map$1.collect(SafeCollector.common.kt:114) в kotlinx.coroutines.flow.FlowKt__CollectKt.emitAll(Collect.kt:109) ) в kotlinx.coroutines.flow.FlowKt.emitAll(Unknown Source:1) в androidx.datastore.core.SingleProcessDataStore$data$1.invokeSuspend(SingleProcessDataStore.kt:117) в androidx.datastore.core.SingleProcessDataStore$data$1.invoke (Неизвестный источник: 8) в androidx.datastore.core.SingleProcessDataStore$data$1.invoke (Неизвестный источник: 4) в kotlinx.coroutines.flow.SafeFlow.collectSafely(Builders.kt:61) в kotlinx.coroutines.flow.AbstractFlow .collect(Flow.kt:230) по адресу com.example.comprinhas.data.PreferencesRepository$special$$inlined$map$2.collect(SafeCollector.common.kt:113) по адресу androidx.compose.runtime.SnapshotStateKt__SnapshotFlowKt$collectAsState$1. вызватьSuspend(SnapshotFlow.kt:64) на androidx.compose.runtime.SnapshotStateKt__SnapshotFlowKt$collectAsState$1.invoke(Неизвестный источник:8) на androidx.compose.runtime.SnapshotStateKt__SnapshotFlowKt$collectAsState$1.invoke(Неизвестный источник:4) на androidx.compose .runtime.SnapshotStateKt__ProduceStateKt$produceState$3.invokeSuspend(ProduceState.kt:150) в kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) в kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:1) 06) в androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81) в androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41) в androidx.compose.ui .platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57) на android.os.Handler.handleCallback(Handler.java:942) на android.os.Handler.dispatchMessage(Handler.java:99) на android .os.Looper.loopOnce(Looper.java:211) в android.os.Looper.loop(Looper.java:300) в android.app.ActivityThread.main(ActivityThread.java:8296) в java.lang.reflect. Method.invoke(собственный метод) по адресу com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:559) по адресу com.android.internal.os.ZygoteInit.main(ZygoteInit.java:954) Подавлено: kotlinx .coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl@55e174a, androidx.compose.runtime.BroadcastFrameClock@164a6bb, StandaloneCoroutine{Cancelling}@24a27d8, AndroidUiDispatcher@ac6f731]
Я уже пробовал:
пересобрать проект
удалить весь проект и снова клонировать его из git
удалена большая часть вызовов репозитория из MainActivity и HomeScreen
У меня есть приложение для Android, которое хранит простые значения с помощью Preferences DataStore. У меня нет экземпляров Proto Datastore. Проблема в том, что мое приложение совершенно случайно начинает давать сбой при запуске, обычно после слишком много раз очистки пользовательских данных. Я понятия не имею, почему это происходит, поскольку, похоже, оно срабатывает даже без вмешательства в мой репозиторий DataStore. Это MainActivity (единственное действие):[code]...
val Context.dataStore: DataStore by preferencesDataStore(name = "settings")
class MainActivity : ComponentActivity() { companion object { var isForeground = false }
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)
setContent { val navController = rememberNavController()
val mainviewModel: ComprinhasViewModel = viewModel() val settingsViewModel: SettingsViewModel = viewModel() val receiptsViewModel: ReceiptsViewModel = viewModel()
if (!it.areModulesAvailable()) { Toast.makeText(this, "QRCode não está presente", Toast.LENGTH_SHORT).show()
val moduleInstallRequest = ModuleInstallRequest.newBuilder() .addApi(optionalModuleApi) .build()
moduleInstallCLient.installModules(moduleInstallRequest) .addOnSuccessListener { Toast.makeText(this, "Módulo instalado", Toast.LENGTH_SHORT).show() } .addOnFailureListener { Toast.makeText(this, "Falha ao instalar módulo", Toast.LENGTH_SHORT) .show() } } else { Toast.makeText(this, "QRCode está presente", Toast.LENGTH_SHORT).show() } } .addOnFailureListener { // TODO: tratar falha na obtencao do leitor de qr code } }
private fun notificationsConfiguration() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission( this, Manifest.permission.POST_NOTIFICATIONS ) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 101) } } // TODO: separação para melhor UX
val name = "Adição e remoção de itens" val importance = NotificationManager.IMPORTANCE_DEFAULT val channel = NotificationChannel("list_notifications", name, importance)
val notificationManager: NotificationManager = application.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.createNotificationChannel(channel) } } [/code] Это мой компонуемый домашний экран: [code]... @OptIn(ExperimentalMaterial3Api::class) @Composable fun HomeScreen( viewModel: ComprinhasViewModel, toWelcomeScreen: () -> Unit, toSettingsScreen: () -> Unit, toReceiptsScreen: () -> Unit, showDialog: () -> Unit, ) { val cartList by viewModel.cartList.collectAsState(initial = emptyList()) val shoppingList by viewModel.shoppingList.collectAsState(initial = emptyList()) val homeState by viewModel.uiState.collectAsState(initial = UiState.LOADING)
val scaffoldState = rememberBottomSheetScaffoldState() val scope = rememberCoroutineScope()
LaunchedEffect(key1 = 1) { if (viewModel.appPreferences.welcomeScreen) toWelcomeScreen() else viewModel.getShoppingList() }
[/code] Это мой файл репозитория DataStore: [code]... data class AppPreferences( val welcomeScreen: Boolean, val name: String, val listId: String, val listPassword: String, val lastChanged: Long, )
class PreferencesRepository( private val preferencesDatastore: DataStore , context: Context ) {
private object PreferencesKeys { val WELCOME_SCREEN = booleanPreferencesKey("welcome_screen") val USER_NAME = stringPreferencesKey("user_name") val LIST_ID = stringPreferencesKey("list_id") val LIST_PASSWORD = stringPreferencesKey("list_password") val LAST_CHANGED = longPreferencesKey("last_changed") val UI_STATE = intPreferencesKey("ui_state") }
val preferencesFlow: Flow = preferencesDatastore.data.map { preferences -> val welcomeScreen = preferences[PreferencesKeys.WELCOME_SCREEN] ?: true val name = preferences[PreferencesKeys.USER_NAME] ?: "" val listId = preferences[PreferencesKeys.LIST_ID] ?: "" val listPassword = preferences[PreferencesKeys.LIST_PASSWORD] ?: "" val lastChanged = preferences[PreferencesKeys.LAST_CHANGED] ?: -1 AppPreferences(welcomeScreen, name, listId, listPassword, lastChanged) }
suspend fun updateUiState(state: UiState) { preferencesDatastore.edit{ it[PreferencesKeys.UI_STATE] = state.ordinal} } val uiState: Flow = preferencesDatastore.data.map { val e = it[PreferencesKeys.UI_STATE] ?: UiState.LOADED enumValues().first { it.ordinal == e } }
suspend fun updateNameAndListId(name: String, listId: String) { preferencesDatastore.edit { preferences -> preferences[PreferencesKeys.USER_NAME] = name preferences[PreferencesKeys.LIST_ID] = listId } }
suspend fun updateUserPrefs(name: String, listId: String, listPassword: String) { preferencesDatastore.edit {preferences -> preferences[PreferencesKeys.WELCOME_SCREEN] = false preferences[PreferencesKeys.USER_NAME] = name preferences[PreferencesKeys.LIST_ID] = listId preferences[PreferencesKeys.LIST_PASSWORD] = listPassword } } } [/code] И, наконец, моя трассировка стека: java.util.NoSuchElementException: Массив не содержит элементов, соответствующих предикату. в com.example.comprinhas.data.PreferencesRepository$special$$inlined$map$2$2.emit(Emitters.kt:227) в kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke(SafeCollector.kt:15) в kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke(SafeCollector.kt:15) в kotlinx.coroutines.flow.internal.SafeCollector.emit(SafeCollector.kt:87) в kotlinx.coroutines.flow.internal. SafeCollector.emit(SafeCollector.kt:66) в androidx.datastore.core.SingleProcessDataStore$data$1$invokeSuspend$$inlined$map$1$2.emit(Collect.kt:137) в kotlinx.coroutines.flow.FlowKt__LimitKt$dropWhile$1 $1.emit(Limit.kt:40) в kotlinx.coroutines.flow.StateFlowImpl.collect(StateFlow.kt:396) в kotlinx.coroutines.flow.FlowKt__LimitKt$dropWhile$$inlined$unsafeFlow$1.collect(SafeCollector.common. kt:114) в androidx.datastore.core.SingleProcessDataStore$data$1$invokeSuspend$$inlined$map$1.collect(SafeCollector.common.kt:114) в kotlinx.coroutines.flow.FlowKt__CollectKt.emitAll(Collect.kt:109) ) в kotlinx.coroutines.flow.FlowKt.emitAll(Unknown Source:1) в androidx.datastore.core.SingleProcessDataStore$data$1.invokeSuspend(SingleProcessDataStore.kt:117) в androidx.datastore.core.SingleProcessDataStore$data$1.invoke (Неизвестный источник: 8) в androidx.datastore.core.SingleProcessDataStore$data$1.invoke (Неизвестный источник: 4) в kotlinx.coroutines.flow.SafeFlow.collectSafely(Builders.kt:61) в kotlinx.coroutines.flow.AbstractFlow .collect(Flow.kt:230) по адресу com.example.comprinhas.data.PreferencesRepository$special$$inlined$map$2.collect(SafeCollector.common.kt:113) по адресу androidx.compose.runtime.SnapshotStateKt__SnapshotFlowKt$collectAsState$1. вызватьSuspend(SnapshotFlow.kt:64) на androidx.compose.runtime.SnapshotStateKt__SnapshotFlowKt$collectAsState$1.invoke(Неизвестный источник:8) на androidx.compose.runtime.SnapshotStateKt__SnapshotFlowKt$collectAsState$1.invoke(Неизвестный источник:4) на androidx.compose .runtime.SnapshotStateKt__ProduceStateKt$produceState$3.invokeSuspend(ProduceState.kt:150) в kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) в kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:1) 06) в androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81) в androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41) в androidx.compose.ui .platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57) на android.os.Handler.handleCallback(Handler.java:942) на android.os.Handler.dispatchMessage(Handler.java:99) на android .os.Looper.loopOnce(Looper.java:211) в android.os.Looper.loop(Looper.java:300) в android.app.ActivityThread.main(ActivityThread.java:8296) в java.lang.reflect. Method.invoke(собственный метод) по адресу com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:559) по адресу com.android.internal.os.ZygoteInit.main(ZygoteInit.java:954) Подавлено: kotlinx .coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl@55e174a, androidx.compose.runtime.BroadcastFrameClock@164a6bb, StandaloneCoroutine{Cancelling}@24a27d8, AndroidUiDispatcher@ac6f731] Я уже пробовал: [list] [*]пересобрать проект [*]удалить весь проект и снова клонировать его из git удалена большая часть вызовов репозитория из MainActivity и HomeScreen [/list]