Значение потока, излучающего даже при отсутствии изменений

#android #kotlin-coroutines #flow #android-jetpack-datastore

Вопрос:

У меня есть хранилище данных в моем приложении для Android, где я храню данные своего профиля. и извлекая следующим образом

 suspend fun saveUser(user: User) {
        dataStore.edit {
            it[USER_ID] = user.id
            it[USER_NAME] = user.name
            it[USER_MOBILE] = user.phone
            it[USER_EMAIL] = user.email
            it[USER_IMAGE] = user.image
            it[USER_ADDRESS] = user.address
        }
    }



val userDate = dataStore.data
        .catch { e ->
            if (e is IOException) {
                Log.e("PREFERENCE", "Error reading preferences", e)
                emit(emptyPreferences())
            } else {
                throw e
            }
        }
        .map { pref ->
            val userId = pref[USER_ID] ?: ""
            val userName = pref[USER_NAME] ?: ""
            val userEmail = pref[USER_EMAIL] ?: ""
            val userImage = pref[USER_IMAGE] ?: ""
            val userPhone = pref[USER_MOBILE] ?: ""
            val userAddress = pref[USER_ADDRESS] ?: ""
            User(
                name = userName,
                image = userImage,
                address = userAddress,
                phone = userPhone,
                id = userId,
                email = userEmail
            )
        }
 

Вместе с этим я сохраняю статус доступности Пользователя

  suspend fun saveIsAvailable(boolean: Boolean) {
        dataStore.edit {
            it[USER_IS_AVAILABLE] = boolean
        }
    }
 

Я собираю данные профиля пользователя, подобные этому, в своей модели просмотра

 viewModelScope.launch(Default) {
            RiderDataStore.userDate.collect {
                user.postValue(it)
            }
        }
 

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

Ответ №1:

Это происходит потому, что вы обновляете свойство пользователя (in DataStore ) и в то же время userDate.collect наблюдаете за всеми изменениями, внесенными в пользователя (in DataStore ). В вашем текущем коде нет возможности отличить «хорошие» и «плохие» обновления пользователя.

Поскольку вы , похоже, игнорируете доступность в DataStore Flow вызываемых userDate вами объектах, возвращаемые User объекты действительно должны оставаться идентичными после изменения доступности. Поведение по умолчанию для Kotlin Flow заключается в выделении при каждом изменении, даже если данные идентичны. Но вы можете исправить это, просто добавив .distinctUntilChanged() после map оператора, например:

 val userDate = dataStore.data
        .catch { e ->
            if (e is IOException) {
                Log.e("PREFERENCE", "Error reading preferences", e)
                emit(emptyPreferences())
            } else {
                throw e
            }
        }
        .map { pref ->
            val userId = pref[USER_ID] ?: ""
            val userName = pref[USER_NAME] ?: ""
            val userEmail = pref[USER_EMAIL] ?: ""
            val userImage = pref[USER_IMAGE] ?: ""
            val userPhone = pref[USER_MOBILE] ?: ""
            val userAddress = pref[USER_ADDRESS] ?: ""
            User(
                name = userName,
                image = userImage,
                address = userAddress,
                phone = userPhone,
                id = userId,
                email = userEmail
            )
        }.distinctUntilChanged()
 

См.также документы. Это гарантирует, что идентичные данные не будут передаваться снова и снова.