Status Update
Comments
an...@outlook.com <an...@outlook.com> #2
Branch: androidx-master-dev
commit b90079595f33f58fece04026a97faa0d243acdb1
Author: Yuichi Araki <yaraki@google.com>
Date: Wed Sep 18 16:55:49 2019
Change the way to detect mismatch between POJO and query
This fixes cursor mismatch warnings with expandProjection.
Bug: 140759491
Test: QueryMethodProcessorTest
Change-Id: I7659002e5e0d1ef60fc1af2a625c0c36da0664d8
M room/compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
M room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
M room/compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
M room/compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
M room/compiler/src/test/kotlin/androidx/room/testing/TestProcessor.kt
ro...@google.com <ro...@google.com> #3
js...@gmail.com <js...@gmail.com> #4
Branch: androidx-master-dev
commit bdde5a1a970ddc9007b28de4aa29d60ffa588f08
Author: Yigit Boyar <yboyar@google.com>
Date: Thu Apr 16 16:47:05 2020
Re-factor how errors are dismissed when query is re-written
This CL changes how we handle errors/warnings if query is
re-written.
There was a bug in expandProjection where we would report warnings
for things that Room already fixes automatically (
The solution to that problem (I7659002e5e0d1ef60fc1af2a625c0c36da0664d8)
solved it by deferring validating of columns until after re-write
decision is made. Unfortunately, this required changing PojoRowAdapter
to have a dummy mapping until it is validating, make it hard to use
as it does have a non-null mapping which is not useful.
This CL partially reverts that change and instead rely on the log
deferring logic we have in Context. This way, we don't need to break
the stability of PojoRowAdapter while still having the ability to
drop warnings that room fixes. This will also play nicer when we
have different query re-writing options that can use more information
about the query results.
Bug: 153387066
Bug: 140759491
Test: existing tests pass
Change-Id: I2ec967c763d33d7a3ff02c1a13c6953b460d1e5f
M room/compiler/src/main/kotlin/androidx/room/log/RLog.kt
M room/compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
M room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
M room/compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
jo...@basetis.com <jo...@basetis.com> #5
I have tested alpha04 and it also occurs.
ro...@google.com <ro...@google.com> #6
Would one of you be able to share a code snippet that reproduces this?
Jordi, are you certain that you only have a single instance of DataStore open for your preferences?
ro...@google.com <ro...@google.com> #7
Also can you share how you forced both writes to happen on the same thread?
ra...@gmail.com <ra...@gmail.com> #8
im using this function on onViewCreated
here's my function to check if there is datastored in jetpack datastore
an...@outlook.com <an...@outlook.com> #9
in App.kt class fun getUserPreferences(): UserDataStorePreferences = UserDataStorePreferences(instance)
in Fragment :
signInViewModel.saveToken(it.data.token)
signInViewModel.saveRefreshToken(it.data.refreshToken)
in Repository:
CoroutineScope(Dispatchers.IO).launch {
App.getUserPreferences().saveRefreshToken(refreshToken)
}
ahd here's my datastore class:
package com.montymobile.sands.common
import android.content.Context
import androidx.datastore.DataStore
import androidx.datastore.preferences.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import java.io.IOException
class UserDataStorePreferences(
context: Context
) {
private val applicationContext = context.applicationContext
private val dataStore: DataStore<Preferences>
init {
dataStore = applicationContext.createDataStore(
name = "sns_preferences"
)
}
val getToken: Flow<String?>
get() = dataStore.data.catch {
if (it is IOException) {
it.printStackTrace()
emit(emptyPreferences())
} else {
throw it
}
}.map { preferences ->
preferences[KEY_TOKEN]
}
suspend fun saveTokens(token: String, refreshToken: String) {
dataStore.edit { preferences ->
preferences[KEY_TOKEN] = token
preferences[KEY_REFRESH_TOKEN] = refreshToken
}
}
val getDeviceId: Flow<String?>
get() = dataStore.data.catch {
if (it is IOException) {
it.printStackTrace()
emit(emptyPreferences())
} else {
throw it
}
}.map { preferences ->
preferences[KEY_DEVICE_ID]
}
suspend fun saveDeviceId(deviceId: String) {
dataStore.edit { preferences ->
preferences[KEY_DEVICE_ID] = deviceId
}
}
val getAppVersion: Flow<String?>
get() = dataStore.data.catch {
if (it is IOException) {
it.printStackTrace()
emit(emptyPreferences())
} else {
throw it
}
}.map { preferences ->
preferences[KEY_APP_VERSION]
}
suspend fun saveAppVersion(bookmark: String) {
dataStore.edit { preferences ->
preferences[KEY_APP_VERSION] = bookmark
}
}
val getRefreshToken: Flow<String?>
get() = dataStore.data.catch {
if (it is IOException) {
it.printStackTrace()
emit(emptyPreferences())
} else {
throw it
}
}.map { preferences ->
preferences[KEY_REFRESH_TOKEN]
}
suspend fun saveRefreshToken(refreshToken: String) {
dataStore.edit { preferences ->
preferences[KEY_REFRESH_TOKEN] = refreshToken
}
}
val isLoggedIn: Flow<Boolean?>
get() = dataStore.data
.catch {
if (it is IOException) {
it.printStackTrace()
emit(emptyPreferences())
} else {
throw it
}
}.map { preferences ->
preferences[KEY_LOGGED_IN]
}
suspend fun setLoggedIn(loggedIn: Boolean) {
dataStore.edit { preferences ->
preferences[KEY_LOGGED_IN] = loggedIn
}
}
suspend fun clearTokens() {
dataStore.edit { preferences ->
preferences.remove(KEY_TOKEN)
preferences.remove(KEY_REFRESH_TOKEN)
}
}
companion object {
val KEY_TOKEN = preferencesKey<String>("key_token")
val KEY_DEVICE_ID = preferencesKey<String>("key_device_id")
val KEY_APP_VERSION = preferencesKey<String>("key_app_version")
val KEY_REFRESH_TOKEN = preferencesKey<String>("key_refresh_token")
val KEY_LOGGED_IN = preferencesKey<Boolean>("key_logged_in")
}
}
an...@outlook.com <an...@outlook.com> #10
suspend fun saveToken(token: String) {
dataStore.edit { preferences ->
preferences[KEY_TOKEN] = token
}
}
with
suspend fun saveTokens(token: String, refreshToken: String) {
dataStore.edit { preferences ->
preferences[KEY_TOKEN] = token
preferences[KEY_REFRESH_TOKEN] = refreshToken
}
}
ap...@google.com <ap...@google.com> #11
Branch: androidx-master-dev
commit ed6cbe16562eead7dd1a0042033d9386e686abfb
Author: rohitsat13 <rohitsat@google.com>
Date: Tue Nov 24 11:57:06 2020
Added a better exception and documentation so people ensure that there is only a single instance of DataStore per file.
In
Test: Added new test for concurrent writes from different DataStore.
Bug: 173522155
Relnote: Add a better documentation and exception around concurrent writes from datastores.
Change-Id: Ia98a2c42d9a43bab2af0672f52b8786fe854cdfd
M datastore/datastore-core/src/main/java/androidx/datastore/core/DataStoreFactory.kt
M datastore/datastore-core/src/main/java/androidx/datastore/core/SingleProcessDataStore.kt
M datastore/datastore-preferences-core/src/main/java/androidx/datastore/preferences/core/PreferenceDataStoreFactory.kt
M datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt
M datastore/datastore/src/main/java/androidx/datastore/DataStoreFactory.kt
ro...@google.com <ro...@google.com> #12
Thanks for sharing. I believe what is happening is that you have multiple instances of DataStore open at the same time and they are writing concurrently. When you call DataStore.updateData
it writes to a temp file, then renames the temp file to the actual file name. Since you have two DataStore's writing at the same time, one of the renames seems to be failing (because the file no longer exists).
Each time you call context.createDataStore
it creates a new instance of DataStore (it's not like context.getSharedPreferences
).
You should instead create the DataStore once, then inject the instance where necessary or manage it as a singleton.
If you only have a single instance of DataStore open, then it'll handle the concurrency for you.
js...@gmail.com <js...@gmail.com> #13
I can confirm that in my case I had multiple instances. Now, reusing the same instance it works.
ro...@google.com <ro...@google.com> #14
Thanks, Marking this as fixed assuming that the others had the same problem. We are working on a better way of catching these scenarios.
Description
After starting my app, I encountered another issue. I found that Proto library is not found in the alpha-03 version so I rolled back to version alpha-01. Also, I tried alpha-02. Since then I am having the error below:
Process: com.montymobile.sands, PID: 19928
java.io.IOException: /data/user/0/com.montymobile.sands/files/datastore/sns_preferences.preferences_pb.tmp could not be renamed to /data/user/0/com.montymobile.sands/files/datastore/sns_preferences.preferences_pb
at androidx.datastore.SingleProcessDataStore.writeData$datastore_core_release(SingleProcessDataStore.kt:304)
at androidx.datastore.SingleProcessDataStore.transformAndWrite(SingleProcessDataStore.kt:282)
at androidx.datastore.SingleProcessDataStore$actor$1.invokeSuspend(SingleProcessDataStore.kt:165)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Any help would be appreciated.