Search code examples
androidkotlin-coroutinesandroid-cursorsimplecursoradapterandroid-cursoradapter

How to get a Cursor from Room in a coroutine?


Trying to get this cursor:

@Query("SELECT * FROM category")
fun getCursor() : Cursor

with this code:

        lifecycleScope.launch {
            binding.category.adapter = SimpleCursorAdapter(
                context,
                android.R.layout.simple_spinner_dropdown_item,
                RoomDB.getInstance(context).categories().getCursor(),
                arrayOf("label"),
                arrayOf(android.R.id.text1).toIntArray(),
                CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER
            )
        }

Which yields this exception:

java.lang.IllegalStateException: Cannot access database on the main thread...

Clearly, I'm not accessing the database from the main thread (note the lifecycleScope.launch). Maybe I have to make getCursor suspend?

Easy enough, but this yields weird compile time errors:

Entities and POJOs must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type). - android.database.Cursor

error: Not sure how to convert a Cursor to this method's return type (android.database.Cursor).

public abstract java.lang.Object getCursor(@org.jetbrains.annotations.NotNull()

What is going on here?


Solution

  • It seems that Cursor just doesn't play nice with suspend. I went only for a Cursor, because the CursorAdapter was mentioned in the Spinner guide, in case the choices for the Spinner come from a database. But there is no actual need for a Cursor.

    This just works absolutely fine:

    @Query("SELECT * FROM category")
    suspend fun getAll() : List<Category>
    

    and

        lifecycleScope.launch {
            binding.categories.adapter = ArrayAdapter(
                context,
                android.R.layout.simple_spinner_dropdown_item,
                RoomDB.getInstance(requireContext()).categories().getAll()
            )
        }