How to initialize a flow in viewmodel with a suspend function as parameter

Viewed 1742

I am working with room database and datastore . Here is my code

ViewModel

@HiltViewModel
class SubscriptionViewModel @Inject constructor(
    private val userDataStore: UserDataStore,
    private val walletDao: WalletDao
) : ViewModel() {

val flow: Flow<List<Transaction>> = walletDao.getAllTransactions(userDataStore.getId()) 
 // This shows an error as userDataStore.getId() is a suspend function in DataStore


 init {
        viewModelScope.launch(IO) {
            getWalletAmount()
        }
    }
}

DataStore

 suspend fun getId(): String {
        val preferences = dataStore.data.first()
        return preferences[USER_ID] ?: ""
    }

WalletDao

 @Query("SELECT * FROM recent_transactions where user_id=:user_id")
    fun getAllTransactions(user_id: String): Flow<List<Transaction>>

The problem is I am unable to initialise the flow. I tried initialising it in the init{ } block using lateinit , but while accessing in the fragment it crashes saying flow has not been initialised.

Any solution would help.

2 Answers

You can wrap it in a flow builder.

val flow: Flow<List<Transaction>> = flow {
    val source = walletDao.getAllTransactions(userDataStore.getId())
    emitAll(source)
}

If you want it to pre-load (start getting the first value even before anything collects the flow), then you should turn it into a SharedFlow by tacking this on:

.shareIn(viewModelScope, SharingStarted.Eagerly, replay = 1)

as I know you can call suspend fun in variable it must in init or in function There is another solution

@HiltViewModel
class SubscriptionViewModel @Inject constructor(
    private val userDataStore: UserDataStore,
    private val walletDao: WalletDao
) : ViewModel() {
        
    val flow= MutableStateFlow<List<Transcation>>(listOf())
       
    // then add value in init or anywhere 
    init {
        viewModelScope.launch(IO) {
            flow.emit() // add value here
        }
    }
}
Related