Jona
Jona

Reputation: 283

Update database entry in Room using WorkManager

I am trying to use WorkManager in Android because till now I have done my insert updates using AsyncTask. I'm trying to update user in Room database. I have created a class in Repository to do the process in background but I don't know if this is the right way to code. Also I am a bit confused how to call the method in userViewModel.

Here is my code:

In Repository:

inner class Test(ctx: Context, params: WorkerParameters) : Worker(ctx, params) {

    override fun doWork(): Result {
        fun updateUser(userId : Int , userName :String , userLastname: String){
            userDao.updateUser(userId, userName, userLastname)
        }
        return Result.success()
    }
}

And in viewModel:

private val workManager: WorkManager = WorkManager.getInstance()
fun updateUser(userID: Int, userName: String, userLastname: String)    {
    workManager.enqueue(OneTimeWorkRequest.from(Repository.Test::class.java))

}

Maybe this is not the right way to use WorkManager so I would appreciate it if anyone can help me.

Upvotes: 7

Views: 10247

Answers (2)

ankuranurag2
ankuranurag2

Reputation: 2441

Updated to support Coroutine Worker

You can use your code with minor changes. You can pass your parameters like userId, userName etc to WorkManager using Data class. Also there is no need to make the Worker class an inner class. Just make it an independent class.So basically, you worker class would look something like:

TestWorker.kt

class TestWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx, params) {

    override suspend fun doWork(): Result {
        val userId = inputData.getInt("USER_ID")
        val userName = inputData.getString("USER_NAME")
        val userLastname = inputData.getString("USER_LAST_NAME") 
        AppDatabase.getInstance().userDao.updateUser(userId, userName, userLastname)
        return Result.success()
    }
}

TestViewModel.kt

class TestViewModel : ViewModel() {
    fun updateUser(userId: Int, userName: String, userLastName: String) {
        val worker = OneTimeWorkRequest.Builder(TestWorker::class.java)
        val data = Data.Builder()
        //Add parameter in Data class. just like bundle. You can also add Boolean and Number in parameter.
        data.putInt("USER_ID", userId)
        data.putString("USER_NAME", userName)
        data.putString("USER_LAST_NAME", userLastName)
        //Set Input Data
        worker.setInputData(data.build())
        //enque worker
        WorkManager.getInstance().enqueue(worker.build())
    }
}

Don't forget to make your database singleton like this:

@Database(entities = [User::class],
    version = 1,
    exportSchema = false)
abstract class AppDatabase : RoomDatabase() {

    abstract fun userDao(): UserDao

    companion object {

        // For Singleton instantiation
        @Volatile
        private var instance: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            return instance ?: synchronized(this) {
                instance ?: buildDatabase(context).also { instance = it }
            }
        }

        private fun buildDatabase(context: Context) =
            Room.databaseBuilder(context, AppDatabase::class.java, "userdb")
                .build()
    }
}

Upvotes: 16

Marfin. F
Marfin. F

Reputation: 512

For those of you got error make doWork suspend, you can snippet following answer below.

class TestWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx, params) {
    val context = ctx
    
    override suspend fun doWork(): Result {
        val userId = inputData.getInt("USER_ID")
        val userName = inputData.getString("USER_NAME")
        val userLastname = inputData.getString("USER_LAST_NAME") 
        AppDatabase.getInstance(context).userDao.updateUser(userId, userName, userLastname)
        return Result.success()
    }
}

detail changes:

Worker CoroutineWorker

override suspend fun doWork(): Result

Upvotes: 0

Related Questions