原文链接
前言
对于跨平台的数据存储方案,我们这里使用multiplatform-settings来处理。但是由于本身这里比较简单,存储部分和业务逻辑部分耦合性很低,所以小伙伴们也可以使用expect
+actual
自行处理相关逻辑
实现
引包
implementation("com.russhwolf:multiplatform-settings:1.2.0")
实例创建
引包完成后,我们需要根据不同的平台创建不同的Settings
实例,进行数据交互操作:
expect class SettingsWrapper {
fun createSettings(): Settings
}
对于Desktop/Jvm
平台而言:
actual class SettingsWrapper {
actual fun createSettings(): Settings {
val delegate: Preferences = Preferences.userRoot()
return PreferencesSettings(delegate)
}
}
对于安卓平台而言:
actual class SettingsWrapper(private val context: Context) {
actual fun createSettings(): Settings {
val delegate = context.getSharedPreferences("your_name", Context.MODE_PRIVATE)
return SharedPreferencesSettiangs(delegate)
}
}
其他更多平台,参考官方文档。安卓平台默认的实现为SharedPreferences,但是众所周知目前安卓并不推荐使用SharedPreferences
的解决方案,而是更倾向于用户使用DataStore
进行数据操作处理,因为SharedPreferences
的数据操作是同步处理写入XML
文件中,而DataStore
提供异步操作接口,数据读写操作不会阻塞主线程,故而在数据一致性方面表现更好,而且由于支持异步操作和流式 API,能够更好地处理并发数据操作和线程安全
如果希望使用DataStore
进行数据处理操作,需要引入implementation("com.russhwolf:multiplatform-settings-datastore:1.2.0")
进行Settings
的初始化操作,以及使用协程处理相应异步操作implementation("com.russhwolf:multiplatform-settings-coroutines:1.2.0")
,协程FlowSettings
初始化接口抽象示例如下:
expect class SettingsWrapper {
@OptIn(ExperimentalSettingsApi::class)
fun createSettings(): FlowSettings
}
对于Desktop/Jvm
平台而言:
actual class SettingsWrapper {
@OptIn(ExperimentalSettingsApi::class)
actual fun createSettings(): FlowSettings {
val delegate: Preferences = Preferences.userRoot()
return PreferencesSettings(delegate).toFlowSettings()
}
}
对于安卓平台而言:
actual class SettingsWrapper(private val context: Context) {
companion object {
private val Context.dataStore by preferencesDataStore("your_name")
}
@OptIn(ExperimentalSettingsImplementation::class, ExperimentalSettingsApi::class)
actual fun createSettings(): FlowSettings {
return DataStoreSettings(context.dataStore)
}
}
依赖注入
同前文一样,我们使用Koin
进行依赖注入,对这里不太了解的小伙伴可以参考前文Kotlin Compose Multiplatform下导航解决方案中的Koin部分,
对于Desktop/Jvm
平台而言:
single { SettingsWrapper().createSettings() }
对于安卓平台而言:
single {
SettingsWrapper(
context = MainActivity.mainContext!!
).createSettings()
}
此时我们即可在公共代码部分使用已经实例化的Settings
进行独写操作了,对于普通Settings
而言:
class DataStorageManager(private val settings: Settings) {
private val observableSettings: ObservableSettings by lazy { settings as ObservableSettings }
}
对于FlowSettings
而言:
class DataStorageManager @OptIn(ExperimentalSettingsApi::class) constructor(private val settings: FlowSettings) {
@OptIn(ExperimentalSettingsApi::class)
private val observableSettings: ObservableSettings by lazy { settings.toBlockingObservableSettings() }
//...
}
使用
存储
fun setString(key: String, value: String) {
observableSettings.set(key = key, value = value)
}
读取
如果期望流式读取,则可以使用:
@OptIn(ExperimentalSettingsApi::class)
fun getFlowString(key: String, defaultValue: String) = settings.getStringFlow(key, defaultValue)
否则可以使用:
fun getNonFlowString(key: String, defaultValue: String) = observableSettings.getString(
key = key,
defaultValue = defaultValue,
)