Home > other >  How to Run afterTextChanged off of the main thread?
How to Run afterTextChanged off of the main thread?

Time:11-12

@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?

CodePudding user response:

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.

CodePudding user response:

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

  • Related