Search code examples
kotlinandroid-roomandroid-workmanager

Observe and update Room database within CoroutineWorker


I would like to pass some parameters to a CoroutineWorker, make a query in my room database using this parameter and use the result of the query to run an url connection (obtaining an inputstream). Using the code I can read this problem in Build window: "Type mismatch: inferred type is CoroutineScope but ViewModelStoreOwner was expected".

UserDao

@Dao
interface UserDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun addUser(user: User)

    @Update
    suspend fun updateUser(user: User)

    @Delete
    suspend fun deleteUser(user: User)

    @Query("SELECT * FROM user_table WHERE Name LIKE :name LIMIT 1")
    fun selectUser(name: String): LiveData<User?>?
}

UserRepository

class UserRepository(private val userDao: UserDao) {

    val readAllData: LiveData<List<User>> = userDao.readAllData()

    suspend fun addUser(user: User){
        userDao.addUser(user)
    }

    suspend fun updateUser(user:User){
        userDao.updateUser(user)
    }

    suspend fun deleteUser(user: User){
        userDao.deleteUser(user)
    }

    fun selectUser(name: String): LiveData<User?>? {
        return userDao.selectUser(name)
    }
}

UserViewModel

class UserViewModel(application: Application): AndroidViewModel(application) {

    private val repository: UserRepository

   fun addUser(user: User){
        viewModelScope.launch(Dispatchers.IO) {
            repository.addUser(user)
        }
    }

    fun updateUser(user: User){
        viewModelScope.launch(Dispatchers.IO){
        repository.updateUser(user)
        }
    }

    fun deleteUser(user: User){
        viewModelScope.launch(Dispatchers.IO) {
            repository.deleteUser(user)
        }
    }

    fun selectUser(name: String): LiveData<User?>? {
        return repository.selectUser(name)
    }
}

and this is the worker:

class DownloadingWorker(context: Context,params:WorkerParameters) : CoroutineWorker(context, params) {

     private lateinit var mUserViewModel: UserViewModel

    override suspend fun doWork(): Result = withContext(Dispatchers.IO) {

        try {
            val Name = inputData.getString("Name")
            mUserViewModel = ViewModelProvider(this).get(UserViewModel::class.java)
            val LiveDataSelectedUser = mUserViewModel.selectUser(name = Name)

            LiveDataSelectedUser.observe(this, object : Observer<User?>(){
                fun downloadfunction(@Nullable user: User?) {
                    val UserUrl = user.url


            val url: URL? = try {
                URL(UserUrl)
            }catch (e: MalformedURLException){
                Log.d("Exception", e.toString())
                null
            }
            
            var list = mutableListOf<DownloadedData>()
            url?.getStream()?.apply {
                withContext(Dispatchers.Default){
                    list = parseDOM(this@apply) as MutableList<DownloadedData>
                }}

            //// then I would like to update user with the downloaded data


                }}  )

 Result.success()
        } catch (error: Throwable) {
            Result.failure()
        }

    }
}

Thank you for your suggestions


Solution

  • Solved passing from Livedata to Data with suspend fun in Coroutine. In UserDao:

    @Query("SELECT * FROM user_table WHERE Name LIKE :name LIMIT 1")
    suspend fun selectUser(name: String): List<User>
    

    In Repository:

    suspend fun selectUser(name: String): List<User> {
        return userDao.selectUser(name = name)
    }
    

    In the worker I can retrieve data in this manner:

        override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
    
            try {
                val Name = inputData.getString("Name")
                val database = getDatabase(applicationContext)
                val repository = UserRepository(database.userDao())
    
                        return withContext(Dispatchers.IO){
                try {
                    val user =  repository.selectUser(name)
                    for(singleUser in user){
                    val UserUrl = singleUser.url
    
    val url: URL? = try {
                    URL(UserUrl)
                }catch (e: MalformedURLException){
                    Log.d("Exception", e.toString())
                    null
                }
                
                var list = mutableListOf<DownloadedData>()
                url?.getStream()?.apply {
                    withContext(Dispatchers.Default){
                        list = parseDOM(this@apply) as MutableList<DownloadedData>
                    }}}
                    }
    
    Result.success()
    
                }catch (e: Exception){
                    Result.failure()
                }
            }
     return Result.success()
        }
    
    }
    

    Maybe it is not the perfect solution, but it works and hopefully it will be useful for someone else.