标签: android-jetpack-datastore

DataStore 未收到来自 Flow 的事件

我正在使用 datastore-preferences:1.0.0-alpha01 并且当数据存储值更新时我似乎无法恢复事件。我一直试图在片段和父活动中观察它,结果相同。当我创建 DataStore 的实例并观察值流时,我在声明观察者后立即收到一个事件(注册观察者后似乎很常见)。这将表明流正在运行,并且观察者正在按预期接收事件。然后我在同一个观察者内部更新首选项的值,该观察者从不接收事件。

我使用这篇文章作为参考https://medium.com/scalereal/hello-datastore-bye-sharedpreferences-android-f46c610b81d5,它与我用来比较我的实现的 repo 一起使用。显然,这个是有效的。https://github.com/PatilShreyas/DataStoreExample

数据存储实用程序

class DataStoreUtils(context: Context) {

    companion object {
        private const val TAG = "DataStoreUtils"
    }

    private val dataStore = context.createDataStore(name = Constants.PrefName.APP_PREFS)

    suspend fun setString(prefKey: String, value: String) {
        Log.d(TAG, "Setting $prefKey to $value")
        dataStore.edit { it[preferencesKey<String>(prefKey)] = value }
    }

    suspend fun getString(prefKey: String): String? {
        return dataStore.data.map { it[preferencesKey<String>(prefKey)] ?: return@map null }.first()
    }

    val usernameFlow: Flow<String?> = dataStore.data
        .catch {
            if (it is IOException) {
                it.printStackTrace() …
Run Code Online (Sandbox Code Playgroud)

android android-lifecycle kotlin-flow android-jetpack-datastore

6
推荐指数
0
解决办法
701
查看次数

Android Jetpack 数据存储“限制”

由于当共享首选项数据超过 1428.51-kb 时会出现内存异常,因此推荐的 Android Jetpack DataStore 是否具有相同的内存限制?

由于 DataStore 使用带有协议缓冲区的类型化对象,因此在内存方面会有优势吗?

android sharedpreferences android-jetpack-datastore

6
推荐指数
1
解决办法
845
查看次数

java.lang.IllegalStateException:在将 NavBackStackEntry 的 ViewModel 添加到 NavController 的返回堆栈之前,您无法访问它

我创建了一个composable名为 ResolveAuth. ResolveAuth 是用户在 Splash 后打开应用程序时的第一个屏幕。它所做的只是检查数据存储中是否存在电子邮件。如果是,则重定向到主屏幕,如果不是,则重定向到教程屏幕

这是我的composable代码viewmodel

@Composable
fun ResolveAuth(resolveAuthViewModel: ResolveAuthViewModel, navController: NavController) {

Scaffold(content = {
    ProgressBar()

    when {
        resolveAuthViewModel.userEmail.value != "" -> {
            navController.navigate(Screen.Main.route) {
                popUpTo(0)
            }
            resolveAuthViewModel.userEmail.value = null
        }
        resolveAuthViewModel.userEmail.value == "" -> {
            navController.navigate(Screen.Tutorial.route) {
                popUpTo(0)
            }
            resolveAuthViewModel.userEmail.value = null
        }
    }
})
}


@HiltViewModel
class ResolveAuthViewModel @Inject constructor(
    private val dataStoreManager: DataStoreManager): ViewModel(){

    val userEmail = MutableLiveData<String>()

    init {
        viewModelScope.launch{
           val job = async {dataStoreManager.email.first()}
           val email = job.await() …
Run Code Online (Sandbox Code Playgroud)

android kotlin android-jetpack-navigation android-jetpack-compose android-jetpack-datastore

6
推荐指数
1
解决办法
2963
查看次数

数据存储·链接序列化器/默认值

核心问题是我想为子消息设置默认值。由于 proto3 不允许在 proto 文件中设置默认值。

示例 Protobuf

message Person {
  int32 age = 1;
  repeated Doggo doggos = 2;
}

message Doggo {
  int32 rating = 1;
}
Run Code Online (Sandbox Code Playgroud)

串行器示例

object PersonSerializer : Serializer<Person> {
    override val defaultValue: Person =
        Person.getDefaultInstance().toBuilder()
            .setAge(1)
            .build()

    override suspend fun readFrom(input: InputStream): Person {
        try {
            return Person.parseFrom(input)
        } catch (exception: InvalidProtocolBufferException) {
            throw CorruptionException("Cannot read proto.", exception)
        }
    }

    override suspend fun writeTo(t: Person, output: OutputStream) {
        t.writeTo(output)
    }
}
Run Code Online (Sandbox Code Playgroud)

这可以将所有 Person 的默认年龄设置为 1。标准值为0。 …

android protobuf-java android-jetpack-datastore

6
推荐指数
0
解决办法
1304
查看次数

从 DataStore 读取一次值以更新片段中的选项菜单复选框状态

我将选项菜单复选框项的状态(选中/未选中)保存在 Jetpack DataStore 中:

override fun onOptionsItemSelected(item: MenuItem) =
    when (item.itemId) {
        R.id.action_hide_completed_tasks -> {
            item.isChecked = !item.isChecked
            viewModel.hideCompleted(item.isChecked)
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
Run Code Online (Sandbox Code Playgroud)

它调用这个方法:

suspend fun updateHideCompleted(hideCompleted: Boolean) {
    dataStore.edit { preferences ->
        preferences[PreferencesKeys.HIDE_COMPLETED] = hideCompleted
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,当我的片段出现在屏幕上时,我想恢复此复选框状态。但由于 Jetpack DataStore 以 的形式提供用户首选项Flow,这感觉有点 hacky。我从中收集并使用运算符仅执行一次,因为此后我不再需要从首选项中更新复选框,当我单击选项菜单项时状态会自动更改FlowonPrepareOptionsMenutake(1)

override fun onPrepareOptionsMenu(menu: Menu) {
    lifecycleScope.launch {
        viewModel.preferencesFlow
            .take(1) // I want this to update only when the fragment comes onto the screen, afterward it's unnecessary
            .collect { …
Run Code Online (Sandbox Code Playgroud)

android android-architecture-components android-jetpack android-jetpack-datastore

5
推荐指数
1
解决办法
1002
查看次数

Android:如何仅创建一个 DatabaseRepository.kt 实例并在不同的活动中使用它?

EDIT: I NEED TO PASS A CONTEXT AS A PARAMETER TO THE CLASS

DataStorerepository同一个班级,不要混淆)

我有两项活动,AB一项repository。ActivityA打开 Activity B,ActivityB将数据保存在repositoryDataStoreAndroid jetpack 的一部分)中。

LiveData在这两个活动中都使用来观察DataStore.

更新DataStorefrom 活动中的新值后BLiveData活动中的B会按预期获取新的更新值。但是,当我返回活动时,ALiveData获取旧数据(期望新的更新数据)。

我意识到这种情况正在发生,因为我repository在这两个活动中创建了两个实例。

我怎样才能只创建该类的一个实例repository并在这两个活动中使用它?如果有更好的方法来做到这一点,那么该解决方案也受到欢迎。

singleton android repository kotlin android-jetpack-datastore

5
推荐指数
1
解决办法
2855
查看次数

无法在 jetpack 数据存储类中写入首选项未找到异常

我正在使用 jetpack 数据存储来存储用户首选项。我要完美地检索数据,但是当我尝试在数据存储中写入数据时,它给了我一个错误。附加了错误,它是一个未找到的类异常我不知道依赖项是否有问题,或者只是我有问题。

这是我用来处理数据存储的类

enum class UiMode {

    LIGHT,DARK
}

class DarkModeManager (context : Context){

    private val dataStore = context.createDataStore("settings")

    val uiModeFlow: Flow<UiMode> = dataStore.data
        .catch {
            if (it is IOException) {
                it.printStackTrace()
                emit(emptyPreferences())
            } else {
                throw it
            }
        }
        .map { preference ->
            val isDarkMode = preference[IS_DARK_MODE] ?: false

            when (isDarkMode) {
                true -> UiMode.DARK
                false -> UiMode.LIGHT
            }
        }

    suspend fun setUiMode(uiMode: UiMode) {
        dataStore.edit { preferences ->
            preferences[IS_DARK_MODE] = when (uiMode) {
                UiMode.LIGHT -> false
                UiMode.DARK …
Run Code Online (Sandbox Code Playgroud)

android kotlin android-jetpack android-jetpack-datastore

4
推荐指数
1
解决办法
1358
查看次数

当我尝试在 onValueChange 中保存 OutlinedTextField 的值时,打字时光标向左跳一个位置

我在使用 OutlinedTextField 和连接到存储用户设置的数据存储时遇到一些问题。数据已保存并正确读取。但是,更新显示和光标似乎存在问题。当我输入文本时(可能是因为我打字太快),光标向左跳一位。这会破坏输入并且用户体验非常糟糕。

到目前为止我还没有找到解决问题的方法。你知道它可能是什么吗?非常感谢!

这就是我用于 OutlinedTextField 的代码:

OutlinedTextField(
    value = dataStoreState.nickname,
    onValueChange = {
        CoroutineScope(Dispatchers.IO).launch {
            viewModel.saveToDataStore(dataStoreState.copy(nickname = it))
        }
    },
    label = { Text(stringResource(id = R.string.enterNickname)) },
    keyboardOptions = KeyboardOptions.Default.copy(
        keyboardType = KeyboardType.Text,
        imeAction = ImeAction.Done
    ),
    modifier = Modifier.fillMaxWidth()
) 
Run Code Online (Sandbox Code Playgroud)

我尝试将文本值缓存在另一个变量中,但没有效果。然后我尝试更改保存功能,但我在这里也找不到正确的解决方案。

android-jetpack-compose android-jetpack-datastore

4
推荐指数
1
解决办法
899
查看次数

为什么 Android Datastore 在运行阻塞时总是返回相同的值

我已经使用数据存储很长时间了。今天我必须读取主线程中的值。查看文档后,我决定使用runblocking。我创建了一个长值,其名称为lastInsertedId。

我在片段 A 中读取了lastInsertedId,然后导航到片段B,并且我正在更改lastInsertedId 的值。当我回到片段 A 时,我再次阅读了lastInsertedId。但lastInsertedId的值仍然相同。实际上它的值正在改变,但我无法读取它的最后一个值。

我认为这是因为碎片A没有被破坏。只有 onDestroyView 是从 onCreateView 调用并创建的。我想要的是只要我想在主线程中访问lastInsertedID 的当前值。

当我将其创建为变量时,它总是返回相同的值。但当我将它转换为函数时,它运行良好。但我不认为这是最佳实践。访问此值的最佳方式是什么?谢谢。

private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "main")

@Singleton
class DataStoreManager @Inject constructor(@ApplicationContext appContext: Context) {

    private val mainDataStore = appContext.dataStore

    suspend fun setLastInsertedId(lastId: Long) {
        mainDataStore.edit { main ->
            main[LAST_INSERTED_ID] = lastId
        }
    }

    // Returns always the same value
    val lastInsertedId: Long = runBlocking {
        mainDataStore.data.map { preferences ->
            preferences[LAST_INSERTED_ID] ?: 0
        }.first()
    }

    // Returns as expected
    fun lastInsertedId(): Long = …
Run Code Online (Sandbox Code Playgroud)

android kotlin kotlin-coroutines android-jetpack-datastore

3
推荐指数
1
解决办法
1488
查看次数

Android 首选项数据存储流不会发出相同的值

只是测试Preferences DataStore并发现提供的Flow输出不会发出相同的值,我的设置如下:

数据存储实用程序类:

object DataStore {
    private val Context.settings by preferencesDataStore("settings") 

    suspend fun saveBoolean(context: Context, keyResId: Int, value: Boolean) {
        val key = booleanPreferencesKey(context.getString(keyResId))

        context.settings.edit {
            it[key] = value
        }
    }

    fun getBooleanFlow(context: Context, keyResId: Int, defaultValueResId: Int): Flow<Boolean> {
        val key = booleanPreferencesKey(context.getString(keyResId))
        val defaultValue = context.resources.getBoolean(defaultValueResId)

        return context.settings.data.map {
            it[key] ?: defaultValue
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

视图模型类:

class FirstViewModel(application: Application) : AndroidViewModel(application) {
    private val uiScope = viewModelScope

    val isUpdateAvailable = DataStore.getBooleanFlow(
        getApplication(), R.string.is_update_available_key, R.bool.is_update_available_default …
Run Code Online (Sandbox Code Playgroud)

android android-preferences sharedpreferences kotlin-flow android-jetpack-datastore

3
推荐指数
1
解决办法
2430
查看次数