skip to Main Content

@Entity Creature

I am attempting to update the name property in my database.

@Entity(primaryKeys = ["name"])
data class Creature(
    @ColumnInfo(defaultValue = "New Creature") val name: String
)

@Dao CreatureDao

The query which updates the name is here, in the DAO.

@Dao
interface CreatureDao {

    [...]

    // update creature name
    @Query("UPDATE Creature SET name=:newName WHERE name=:oldName")
    fun updateCreatureName(oldName: String, newName: String)
}

MyRepository

My view model makes the query via my repository

class MyRepository(private val creatureDao: CreatureDao) {

    [...]

    // update creature name
    @Suppress("RedundantSuspendModifier")
    @WorkerThread
    suspend fun updateCreatureName(oldName: String, newName: String) {
        creatureDao.updateCreatureName(oldName, newName)
    }
}

SharedViewModel

This is where my view model makes the call to update the name property

class SharedViewModel(
    private val repository: MyRepository
) : ViewModel() {

    [...]

    fun updateCreatureName(oldName: String, newName: String) {
        viewModelScope.launch { repository.updateCreatureName(oldName, newName) }
    }
}

AboutFragment

This view model’s updateCreatureName() method is called from AboutFragment when the nameTextInputEditText is changed…

class AboutFragment() : Fragment() {

    [...]

        // update creature record when creature name is edited
        binding.nameTextInputEditText.addTextChangedListener(object : TextWatcher {
            private lateinit var oldName: String
            private lateinit var newName: String

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                oldName = s.toString()
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                newName = s.toString()
            }

            override fun afterTextChanged(s: Editable?) {
                sharedViewModel.updateCreatureName(oldName, newName)
            }

        })
    }
}

Problem

I receive error

java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

When I try to launch the activity fragment. How can I run

override fun afterTextChanged()

off of the main thread?

2

Answers


  1. Chosen as BEST ANSWER

    The key was to use

    viewModelScope.launch(Dispatcher.IO){...}
    

    instead of

    viewModelScope.launch{...}
    

    "When you don't pass a Dispatcher to launch, any coroutines launched from viewModelScope run in the main thread." source


  2. You could use a ExecutorService and then call the method submit() passing a Runnable. Create a single instance in you class or inject a Singleton in case you are using dependency injection.
    Maybe the Jetpack framework is providing here some better ideas also.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search