英文:
Android DataStore : how to create it with a dynamic filename?
问题
私有字段datastore
已经使用了DATA_STORE_FILENAME
和WeatherInfoSerializer
来创建DataStore。如果您想使用不同的fileKey
来创建DataStore,您可以考虑将DATA_STORE_FILENAME
和WeatherInfoSerializer
作为参数传递给getDataStore
方法,并在该方法内部使用fileKey
来创建DataStore。以下是一种可能的实现方式:
override suspend fun getDataStore(
context: Context,
fileKey: String
): DataStore<SingleWidgetInfo> {
val dataStore = context.dataStoreBuilder(
name = DATA_STORE_FILENAME + fileKey, // Use fileKey to create a unique name
serializer = WeatherInfoSerializer
).build()
return dataStore
}
这样,每次调用getDataStore
方法时,将使用不同的fileKey
创建一个新的DataStore,从而实现了根据fileKey
创建不同的DataStore的目的。
英文:
Based on the following Kotlin code (from Glance AppWidget), how can I inject the fileKey in the dataStore()
method (which seems possible due to the comment above) ?
/**
* Use the same file name regardless of the widget instance to share data between them
*
* If you need different state/data for each instance, create a store using the provided fileKey
*/
private val Context.datastore by dataStore(DATA_STORE_FILENAME, WeatherInfoSerializer)
override suspend fun getDataStore(
context: Context,
fileKey: String
): DataStore<SingleWidgetInfo> {
return context.datastore // How to use fileKey while creating the datastore ?
}
What I tried failed :
Thanks
答案1
得分: 1
以下是您提供的代码的翻译部分:
已经搞定了,但不太美观。`dateStore` 下面的代码不是公开的,所以我不得不复制/粘贴/调整了一些代码:
object SingleWidgetDataStateDefinition : GlanceStateDefinition<SingleWidgetData> {
private const val DATA_STORE_FILENAME = "singleWidget"
//private val Context.datastore by dataStore(DATA_STORE_FILENAME, SingleWidgetDataSerializer)
override suspend fun getDataStore(
context: Context,
fileKey: String
): DataStore<SingleWidgetData> {
return DataStoreSingletonDelegate(
serializer = SingleWidgetDataSerializer,
fileName = DATA_STORE_FILENAME + fileKey,
corruptionHandler = null,
produceMigrations = { listOf() },
scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
).getValue(context)
}
}
and
class DataStoreSingletonDelegate<T> internal constructor(
private val fileName: String,
private val serializer: Serializer<T>,
private val corruptionHandler: ReplaceFileCorruptionHandler<T>?,
private val produceMigrations: (Context) -> List<DataMigration<T>>,
private val scope: CoroutineScope
) {
private val lock = Any()
@GuardedBy("lock")
@Volatile
private var INSTANCE: DataStore<T>? = null
fun getValue(thisRef: Context): DataStore<T> {
return INSTANCE ?: synchronized(lock) {
if (INSTANCE == null) {
val applicationContext = thisRef.applicationContext
INSTANCE = DataStoreFactory.create(
serializer = serializer,
produceFile = { applicationContext.dataStoreFile(fileName) },
corruptionHandler = corruptionHandler,
migrations = produceMigrations(applicationContext),
scope = scope
)
}
INSTANCE!!
}
}
}
请注意,代码中的注释部分(例如 //private val Context.datastore by dataStore(DATA_STORE_FILENAME, SingleWidgetDataSerializer)
)未被翻译。如果您需要进一步的翻译或有其他问题,请随时提出。
英文:
Got it working, but it's not very pretty. Code underneath dateStore
was not public, So I had to copy/paste/adapt a bit of code :
object SingleWidgetDataStateDefinition : GlanceStateDefinition<SingleWidgetData> {
private const val DATA_STORE_FILENAME = "singleWidget"
//private val Context.datastore by dataStore(DATA_STORE_FILENAME, SingleWidgetDataSerializer)
override suspend fun getDataStore(
context: Context,
fileKey: String
): DataStore<SingleWidgetData> {
return DataStoreSingletonDelegate(
serializer = SingleWidgetDataSerializer,
fileName = DATA_STORE_FILENAME + fileKey,
corruptionHandler = null,
produceMigrations = { listOf() },
scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
).getValue(context)
}
}
and
class DataStoreSingletonDelegate<T> internal constructor(
private val fileName: String,
private val serializer: Serializer<T>,
private val corruptionHandler: ReplaceFileCorruptionHandler<T>?,
private val produceMigrations: (Context) -> List<DataMigration<T>>,
private val scope: CoroutineScope
) {
private val lock = Any()
@GuardedBy("lock")
@Volatile
private var INSTANCE: DataStore<T>? = null
fun getValue(thisRef: Context): DataStore<T> {
return INSTANCE ?: synchronized(lock) {
if (INSTANCE == null) {
val applicationContext = thisRef.applicationContext
INSTANCE = DataStoreFactory.create(
serializer = serializer,
produceFile = { applicationContext.dataStoreFile(fileName) },
corruptionHandler = corruptionHandler,
migrations = produceMigrations(applicationContext),
scope = scope
)
}
INSTANCE!!
}
}
}
答案2
得分: 1
我能够从 Kotlin Slack 群组中的 Glance 频道得到帮助。以下更改非常简单,可以直接添加到示例 WeatherApp 中,并且仅在工作器中更改一两行(以便每个小部件显示不同的信息以进行测试)。
// 为了更清晰,将DATA_STORE_FILENAME重命名为DATA_STORE_FILENAME_PREFIX
private const val DATA_STORE_FILENAME_PREFIX = "weatherInfo_"
// 以下行可以移除,因为不再需要
//private val Context.datastore by dataStore(DATA_STORE_FILENAME, WeatherInfoSerializer)
// getDataStore 现在使用 DataStoreFactory
override suspend fun getDataStore(context: Context, fileKey: String) = DataStoreFactory.create(
serializer = WeatherInfoSerializer,
produceFile = { getLocation(context, fileKey) }
)
override fun getLocation(context: Context, fileKey: String) =
context.dataStoreFile(DATA_STORE_FILENAME_PREFIX + fileKey.lowercase())
英文:
I was able to get help from the Kotlin slack group which has a Glance channel. The change below is quite simple and is able to be added directly to the example WeatherApp and only changes a line or two in the worker (so that each widget displays different information for testing purposes).
// Rename DATA_STORE_FILENAME for clarity
private const val DATA_STORE_FILENAME_PREFIX = "weatherInfo_"
// The below line can be removed as it is no longer needed
//private val Context.datastore by dataStore(DATA_STORE_FILENAME, WeatherInfoSerializer)
// getDataStore now uses DataStoreFactory
override suspend fun getDataStore(context: Context, fileKey: String) = DataStoreFactory.create(
serializer = WeatherInfoSerializer,
produceFile = { getLocation(context, fileKey) }
)
override fun getLocation(context: Context, fileKey: String) =
context.dataStoreFile(DATA_STORE_FILENAME_PREFIX + fileKey.lowercase())
答案3
得分: 0
dataStore
函数不会返回DataStore
本身,而是用于与by
关键字一起使用。我不太确定,但我认为这可能会起作用:
override suspend fun getDataStore(
context: Context,
fileKey: String
): DataStore<SingleWidgetInfo> {
val store by dataStore(DATA_STORE_FILENAME + fileKey, WeatherInfoSerializer)
return store
}
英文:
the dataStore
function doesn't return a DataStore
itself but is meant to be used together with the by
keyword. I'm not entirely sure but I believe this might work:
override suspend fun getDataStore(
context: Context,
fileKey: String
): DataStore<SingleWidgetInfo> {
val store by dataStore(DATA_STORE_FILENAME + fileKey, WeatherInfoSerializer)
return store
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论