debaser
debaser

Reputation: 23

Passing variables to Kotlin Coroutine in Android

I have a fragment, viewmodel and database. I call this method in the viewModel from the fragment which deletes data from database by a list of id's.

    fun deleteDefects(idList: List<Long>) {
        Log.d("RoundViewModel", idList.toString())
        viewModelScope.launch(Dispatchers.IO) {
            Log.d("RoundViewModel", idList.toString())
            ddb.dao().delAddedDefect(idList)
        }
    }

It works.. sometimes, about 2 or 3 times out of 10, deletes data. And sometimes idList in launch is empty.

2020-06-26 18:40:44.461 18524-18524/ru.debaser.projects.inspectionsheet D/RoundViewModel: [259, 260]
2020-06-26 18:40:44.464 18524-18555/ru.debaser.projects.inspectionsheet D/RoundViewModel: []
2020-06-26 18:40:47.453 18524-18524/ru.debaser.projects.inspectionsheet D/RoundViewModel: [264, 267]
2020-06-26 18:40:47.457 18524-18555/ru.debaser.projects.inspectionsheet D/RoundViewModel: []
2020-06-26 18:40:50.838 18524-18524/ru.debaser.projects.inspectionsheet D/RoundViewModel: [276, 267]
2020-06-26 18:40:50.841 18524-18555/ru.debaser.projects.inspectionsheet D/RoundViewModel: []
2020-06-26 18:40:53.896 18524-18524/ru.debaser.projects.inspectionsheet D/RoundViewModel: [276, 267, 264]
2020-06-26 18:40:53.899 18524-18555/ru.debaser.projects.inspectionsheet D/RoundViewModel: []
2020-06-26 18:40:56.947 18524-18524/ru.debaser.projects.inspectionsheet D/RoundViewModel: [259, 260, 264]
2020-06-26 18:40:56.950 18524-18555/ru.debaser.projects.inspectionsheet D/RoundViewModel: []
2020-06-26 18:41:00.023 18524-18524/ru.debaser.projects.inspectionsheet D/RoundViewModel: [264, 265, 267]
2020-06-26 18:41:00.027 18524-18554/ru.debaser.projects.inspectionsheet D/RoundViewModel: []
2020-06-26 18:41:02.731 18524-18524/ru.debaser.projects.inspectionsheet D/RoundViewModel: [264, 265]
2020-06-26 18:41:02.733 18524-18554/ru.debaser.projects.inspectionsheet D/RoundViewModel: []
2020-06-26 18:41:08.200 18524-18524/ru.debaser.projects.inspectionsheet D/RoundViewModel: [277, 267]
2020-06-26 18:41:08.201 18524-18554/ru.debaser.projects.inspectionsheet D/RoundViewModel: []
2020-06-26 18:41:11.694 18524-18524/ru.debaser.projects.inspectionsheet D/RoundViewModel: [264, 259]
2020-06-26 18:41:11.695 18524-18554/ru.debaser.projects.inspectionsheet D/RoundViewModel: [264, 259]
2020-06-26 18:41:19.528 18524-18524/ru.debaser.projects.inspectionsheet D/RoundViewModel: [265, 267]
2020-06-26 18:41:19.530 18524-18591/ru.debaser.projects.inspectionsheet D/RoundViewModel: []
2020-06-26 18:41:23.780 18524-18524/ru.debaser.projects.inspectionsheet D/RoundViewModel: [276, 267]
2020-06-26 18:41:23.782 18524-18556/ru.debaser.projects.inspectionsheet D/RoundViewModel: [276, 267]

Upvotes: 2

Views: 2251

Answers (2)

Dominic Fischer
Dominic Fischer

Reputation: 1849

The code you have should just work but it looks like you're doing something naughty when calling deleteDefects.

List<...> is a read-only interface and it does not guarantee immutability. I imagine you are modifying the idList after you pass it into the function. Something like this...

val idList = mutableListOf<Long>()
idList.add(50)
idList.add(20)

deleteDefects(idList)
idList.clear()

This is a race condition! Since concurrency has been introduced in deleteDefects, you shouldn't touch idList after you pass it in.. ever. Unless you use locks or similar.

A quick fix would be to make a defensive copy, like so.

fun deleteDefects(idListTmp: List<Long>) {
    val idList = idListTmp.toList() // Safe!
    Log.d("RoundViewModel", idList.toString())
    viewModelScope.launch(Dispatchers.IO) {
        Log.d("RoundViewModel", idList.toString())
        ddb.dao().delAddedDefect(idList)
    }
}

A proper fix, would be to not modify idList after you call deleteDefacts(idList).

Another proper fix could be to just do deleteDefacts(idList.toList()).

Upvotes: 4

Van Tran
Van Tran

Reputation: 41

The thread in the caller (function deleteDefects) won't wait until the callee finish (sometimes). To test it out, wrap it in runBlocking.

Suggestion: Using await or join.

This article could help figure it out.

Upvotes: 0

Related Questions