Why does suspend doesn't work with LiveData?

Viewed 745

I'm trying to rewrite my Kotlin database interface to use it with coroutines, so I made all the functions suspend. But when I run the application I get the error: Not sure how to convert a Cursor to this method's return type.

Failing code:

@Dao
interface PostDao {
    @Query("SELECT * FROM post")
    suspend fun getAll(): LiveData<List<Post>>
}

The function which failed the build returns the LiveData object and this seems to be the problem, because if I remove the "suspend" word or LiveData, the app works properly.

Working variant:

@Dao
interface PostDao {
    @Query("SELECT * FROM post")
    fun getAll(): LiveData<List<Post>>
}

Could anyone explain why does it work so? Is there a way to use suspend with function returning LiveData?

1 Answers

It doesn't really make sense to use a suspend function to return a LiveData. Generating a LiveData instance is a non-blocking action, so there's no reason for it to suspend. In the case of LiveData, the blocking data request happens in the background and updates the already-returned LiveData when it's ready, rather than waiting for the data and then generating the LiveData.

If you use a suspend function for your data, you would just return List<Post>. Calling this suspend function would make the request a single time, suspend until the data is ready, and then return it in your coroutine.

If you want to continually receive updated data, what you need is a coroutine Flow. Since a Flow is cold, you do not use a suspend function for it:

@Dao
interface PostDao {
    @Query("SELECT * FROM post")
    fun getAll(): Flow<List<Post>>
}

Then in your view model layer, you can either convert it to a LiveData:

val postsLiveData = repository.getAll().asLiveData()

or you can convert it to a hot StateFlow or SharedFlow, where consensus seems to be that it should be preferred over LiveData since it is not tied directly to Android details:

val postsSharedFlow = repository.getAll().shareIn(viewModelScope, SharingStarted.Eagerly, 1)

You can read about subscribing to SharedFlow and StateFlow in the documentation.

Related