我想观察从ON_START
到ON_STOP
的一些数据,并在按下后退按钮时将其保存到共享首选项。问题是preferencesDataStore.dataStore.edit
前面的代码被调用,但是值没有保存到preferences。
这是我的代码。
视图模型:
@HiltViewModel
class MyViewModel @Inject constructor(
private val repository: Repository
) : ViewModel() {
private val _myUiState = MutableStateFlow<List<Int>>(emptyList())
val myUiState: StateFlow<List<Int>> = _myUiState
// Load data from a suspend fun and mutate state
init {
viewModelScope.launch {
repository.readFlow()
.collect {
_myUiState.value = it
}
}
}
fun saveDataToPreferences() {
viewModelScope.launch {
Log.d(GameApp.TAG, "save data, data=${_myUiState.value}") // this is logged
repository.saveData(_myUiState.value)
}
}
}
片段:
@AndroidEntryPoint
class MyFragment : Fragment(R.layout.fragment_my) {
private val myModel: MyViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Create a new coroutine in the lifecycleScope
viewLifecycleOwner.lifecycleScope.launch {
// repeatOnLifecycle launches the block in a new coroutine every time the
// lifecycle is in the STARTED state (or above) and cancels it when it's STOPPED.
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
// Trigger the flow and start listening for values.
// This happens when lifecycle is STARTED and stops
// collecting when the lifecycle is STOPPED
myModel.myUiState
.collect {
// update the UI
}
}
}
lifecycle.addObserver(GameFragmentLifecycleObserver(gamePlayViewModel))
}
}
class MyFragmentLifecycleObserver(private val model: MyViewModel) : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() = model.saveDataToPreferences()
}
数据层:
interface DataSource {
suspend fun readFlow(): Flow<List<Int>>
suspend fun saveData(data: List<Int>)
}
internal class LocalDataSource(private val preferencesDataStore: PreferencesDataStore) : DataSource {
override fun readFlow(): Flow<List<Int>> =
preferencesDataStore.dataStore.data
.catch { exception ->
// dataStore.data throws an IOException when an error is encountered when reading data
if (exception is IOException) {
emit(emptyPreferences())
} else {
throw exception
}
}
.map { preferences ->
preferences[PreferencesKeys.DATA] ?: emptyList()
}
override suspend fun saveData(list: List<Int>) {
preferencesDataStore.dataStore.edit { preferences ->
preferences[PreferencesKeys.DATA] = list
}
}
}
private const val USER_PREFERENCES_NAME = "user_preferences"
private val Context.dataStore by preferencesDataStore(
name = USER_PREFERENCES_NAME
)
interface PreferencesDataStore {
val dataStore: DataStore<Preferences>
}
internal class PreferencesDataStoreImpl(private val context: Context) : PreferencesDataStore {
override val dataStore: DataStore<Preferences>
get() = context.dataStore
}
interface Repository {
fun readFlow(): Flow<List<Int>>
suspend fun saveData(list: List<Int>)
}
internal class RepositoryImpl @Inject constructor(private val dataSource: DataSource) : Repository {
override fun readFlow() = dataSource.readFlow()
override suspend fun saveData(list: List<Int>) = dataSource.saveData(list)
}
柄。
@Module
@InstallIn(ViewModelComponent::class)
internal object ViewModelModule {
@Provides
@ViewModelScoped
fun provideRepository(preferencesDataStore: PreferencesDataStore): Repository = RepositoryImpl(LocalDataSource(preferencesDataStore))
}
build.gradle
ext.hilt_version = "2.35"
def kotlinCoroutinesCore = '1.5.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesCore"
// AndroidX
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
implementation "androidx.fragment:fragment-ktx:1.3.6"
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0-alpha03"
implementation "androidx.datastore:datastore-preferences:1.0.0"
// Hilt
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
我理解我的数据没有保存的原因,因为模型视图范围被取消了,repository.saveData(_myUiState.value)
也被取消了。
我想知道正确的模式是什么。
我决定采用不同的方法,一旦获得数据就保存数据,而不是将其保存在内存中,直到屏幕最小化或关闭。
MyFragmentLifecycleObserver
可以删除
更新。
如果你真的需要保存一次数据(当应用程序进入后台时),你可以使用一个应用范围的作用域。请阅读文章https://medium.com/androiddevelopers/create-an-application-coroutinescope-using-hilt-dd444e721528