Reputation: 4607
I'm trying to get myself familiar with DataStore
, so in my current project, I'm trying to use it.
In my dependency. I've added :
implementation "androidx.datastore:datastore-preferences:1.0.0-alpha06"
Then I created this class to handle data-store:
class BasicDataStore(context: Context) :
PrefsDataStore(
context,
PREF_FILE_BASIC
),
BasicImpl {
override val serviceRunning: Flow<Boolean>
get() = dataStore.data.map { preferences ->
preferences[SERVICE_RUNNING_KEY] ?: false
}
override suspend fun setServiceRunningToStore(serviceRunning: Boolean) {
dataStore.edit { preferences ->
preferences[SERVICE_RUNNING_KEY] = serviceRunning
}
}
companion object {
private const val PREF_FILE_BASIC = "basic_preference"
private val SERVICE_RUNNING_KEY = booleanPreferencesKey("service_running")
}
}
@Singleton
interface BasicImpl {
val serviceRunning: Flow<Boolean>
suspend fun setServiceRunningToStore(serviceRunning: Boolean)
}
In my viewmodel, I'm trying to use that value, like this :
class MainViewModel(application: Application) : AndroidViewModel(application) {
...
private val basicDataStore = BasicDataStore(application)
val serviceRunning
: StateFlow<Boolean> get()
= basicDataStore.serviceRunning as StateFlow<Boolean>
fun setServiceRunning(serviceRunning: Boolean) {
viewModelScope.launch(IO) {
basicDataStore.setServiceRunningToStore(serviceRunning)
}
}
}
But it gives me the following error :
Caused by: java.lang.ClassCastException: com.mua.roti.data.datastore.BasicDataStore$serviceRunning$$inlined$map$1 cannot be cast to kotlinx.coroutines.flow.StateFlow
at com.mua.roti.viewmodel.MainViewModel.getServiceRunning(MainViewModel.kt:33)
...
In xml, in UI part :
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{main.serviceRunning.value.toString()}" />
With viewmodel everything was so cool and easy, easy to read and implement. Now I'm confused with Flow. Thanks.
Upvotes: 6
Views: 10977
Reputation: 7602
The hierarchy of flows is as follows: StateFlow
-> SharedFlow
-> Flow
So you can't really cast it, instead you should use the stateIn() operator if you'd like to convert your cold flow into a hot StateFlow. In your case:
val serviceRunning: StateFlow<Boolean>
get() = basicDataStore.serviceRunning.stateIn(viewModelScope, SharingStarted.Lazily, false)
You might tweak around the SharingStarted
and/or initial value of the stateflow
Upvotes: 19