MutableLiveData: Cannot invoke setValue on a background thread from Coroutine
I'm trying to trigger an update on LiveData from a coroutine:
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
AddressList.value = getAddressList()
}
return AddressList
}
but I get the following error:
IllegalStateException: Cannot invoke setValue on a background thread
Is there a way to make it work with coroutines?
kotlin android-livedata kotlinx.coroutines
add a comment |
I'm trying to trigger an update on LiveData from a coroutine:
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
AddressList.value = getAddressList()
}
return AddressList
}
but I get the following error:
IllegalStateException: Cannot invoke setValue on a background thread
Is there a way to make it work with coroutines?
kotlin android-livedata kotlinx.coroutines
1
Is there a reason you don't want to use postValue?
– RedDeckWins
Nov 14 '18 at 16:28
@RedDeckWins. No, I just didn't take it into account but it is definitely the way to update MutableLiveData from a coroutine.
– kike
Nov 15 '18 at 8:31
add a comment |
I'm trying to trigger an update on LiveData from a coroutine:
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
AddressList.value = getAddressList()
}
return AddressList
}
but I get the following error:
IllegalStateException: Cannot invoke setValue on a background thread
Is there a way to make it work with coroutines?
kotlin android-livedata kotlinx.coroutines
I'm trying to trigger an update on LiveData from a coroutine:
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
AddressList.value = getAddressList()
}
return AddressList
}
but I get the following error:
IllegalStateException: Cannot invoke setValue on a background thread
Is there a way to make it work with coroutines?
kotlin android-livedata kotlinx.coroutines
kotlin android-livedata kotlinx.coroutines
asked Nov 14 '18 at 16:06
kikekike
804727
804727
1
Is there a reason you don't want to use postValue?
– RedDeckWins
Nov 14 '18 at 16:28
@RedDeckWins. No, I just didn't take it into account but it is definitely the way to update MutableLiveData from a coroutine.
– kike
Nov 15 '18 at 8:31
add a comment |
1
Is there a reason you don't want to use postValue?
– RedDeckWins
Nov 14 '18 at 16:28
@RedDeckWins. No, I just didn't take it into account but it is definitely the way to update MutableLiveData from a coroutine.
– kike
Nov 15 '18 at 8:31
1
1
Is there a reason you don't want to use postValue?
– RedDeckWins
Nov 14 '18 at 16:28
Is there a reason you don't want to use postValue?
– RedDeckWins
Nov 14 '18 at 16:28
@RedDeckWins. No, I just didn't take it into account but it is definitely the way to update MutableLiveData from a coroutine.
– kike
Nov 15 '18 at 8:31
@RedDeckWins. No, I just didn't take it into account but it is definitely the way to update MutableLiveData from a coroutine.
– kike
Nov 15 '18 at 8:31
add a comment |
3 Answers
3
active
oldest
votes
You can do one of the following :
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
AddressList.postValue(getAddressList())
}
return AddressList
}
or
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
val adresses = getAddressList()
withContext(Dispatchers.Main) {
AddressList.value = adresses
}
}
return AddressList
}
Actually, I think this is the perfectpostValue()
usage scenario. There is no need to force Main Thread context.
– kike
Nov 15 '18 at 8:24
add a comment |
I just figured out that it's possible by using withContext(Dispatchers.Main){}
:
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
GlobalScope.launch {
withContext(Dispatchers.Main){ AddressList.value = getAddressList() }
}
return AddressList
}
1
Don't callgetAdresseList()
inside thewithContext(Dispatchers.Main)
block because this will be run on the main thread. Call it outside so it's properly dispatched byDispatchers.Default
and use only the result on the main thread
– pdegand59
Nov 14 '18 at 16:30
add a comment |
Although others have pointed out that, in this case, the library provides its own method to post an operation to the main thread, coroutines provide a general solution that works regardless of a given library's functionality.
The first step is to stop using GlobalScope
for background jobs, doing this will lead to leaks where your activity, or scheduled job, or whatever unit of work you invoke this from, may get destroyed, and yet your job will continue in the background and even submit its results to the main thread. Here's what the official documentation on GlobalScope
states:
Application code usually should use application-defined CoroutineScope, using async or launch on the instance of GlobalScope is highly discouraged.
You should define your own coroutine scope and its coroutineContext
property should contain Dispatchers.Main
as the dispatcher. Furthermore, the whole pattern of launching jobs within a function call and returning LiveData
(which is basically another kind of Future
), isn't the most convenient way to use coroutines. Instead you should have
suspend fun getAddresses() = withContext(Dispatchers.Default) { getAddressList() }
and at the call site you should launch
a coroutine, within which you can now freely call getAddresses()
as if it was a blocking method and get the addresses directly as a return value.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53304347%2fmutablelivedata-cannot-invoke-setvalue-on-a-background-thread-from-coroutine%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can do one of the following :
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
AddressList.postValue(getAddressList())
}
return AddressList
}
or
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
val adresses = getAddressList()
withContext(Dispatchers.Main) {
AddressList.value = adresses
}
}
return AddressList
}
Actually, I think this is the perfectpostValue()
usage scenario. There is no need to force Main Thread context.
– kike
Nov 15 '18 at 8:24
add a comment |
You can do one of the following :
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
AddressList.postValue(getAddressList())
}
return AddressList
}
or
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
val adresses = getAddressList()
withContext(Dispatchers.Main) {
AddressList.value = adresses
}
}
return AddressList
}
Actually, I think this is the perfectpostValue()
usage scenario. There is no need to force Main Thread context.
– kike
Nov 15 '18 at 8:24
add a comment |
You can do one of the following :
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
AddressList.postValue(getAddressList())
}
return AddressList
}
or
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
val adresses = getAddressList()
withContext(Dispatchers.Main) {
AddressList.value = adresses
}
}
return AddressList
}
You can do one of the following :
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
AddressList.postValue(getAddressList())
}
return AddressList
}
or
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
val adresses = getAddressList()
withContext(Dispatchers.Main) {
AddressList.value = adresses
}
}
return AddressList
}
answered Nov 14 '18 at 16:28
pdegand59pdegand59
7,10073447
7,10073447
Actually, I think this is the perfectpostValue()
usage scenario. There is no need to force Main Thread context.
– kike
Nov 15 '18 at 8:24
add a comment |
Actually, I think this is the perfectpostValue()
usage scenario. There is no need to force Main Thread context.
– kike
Nov 15 '18 at 8:24
Actually, I think this is the perfect
postValue()
usage scenario. There is no need to force Main Thread context.– kike
Nov 15 '18 at 8:24
Actually, I think this is the perfect
postValue()
usage scenario. There is no need to force Main Thread context.– kike
Nov 15 '18 at 8:24
add a comment |
I just figured out that it's possible by using withContext(Dispatchers.Main){}
:
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
GlobalScope.launch {
withContext(Dispatchers.Main){ AddressList.value = getAddressList() }
}
return AddressList
}
1
Don't callgetAdresseList()
inside thewithContext(Dispatchers.Main)
block because this will be run on the main thread. Call it outside so it's properly dispatched byDispatchers.Default
and use only the result on the main thread
– pdegand59
Nov 14 '18 at 16:30
add a comment |
I just figured out that it's possible by using withContext(Dispatchers.Main){}
:
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
GlobalScope.launch {
withContext(Dispatchers.Main){ AddressList.value = getAddressList() }
}
return AddressList
}
1
Don't callgetAdresseList()
inside thewithContext(Dispatchers.Main)
block because this will be run on the main thread. Call it outside so it's properly dispatched byDispatchers.Default
and use only the result on the main thread
– pdegand59
Nov 14 '18 at 16:30
add a comment |
I just figured out that it's possible by using withContext(Dispatchers.Main){}
:
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
GlobalScope.launch {
withContext(Dispatchers.Main){ AddressList.value = getAddressList() }
}
return AddressList
}
I just figured out that it's possible by using withContext(Dispatchers.Main){}
:
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
GlobalScope.launch {
withContext(Dispatchers.Main){ AddressList.value = getAddressList() }
}
return AddressList
}
answered Nov 14 '18 at 16:20
kikekike
804727
804727
1
Don't callgetAdresseList()
inside thewithContext(Dispatchers.Main)
block because this will be run on the main thread. Call it outside so it's properly dispatched byDispatchers.Default
and use only the result on the main thread
– pdegand59
Nov 14 '18 at 16:30
add a comment |
1
Don't callgetAdresseList()
inside thewithContext(Dispatchers.Main)
block because this will be run on the main thread. Call it outside so it's properly dispatched byDispatchers.Default
and use only the result on the main thread
– pdegand59
Nov 14 '18 at 16:30
1
1
Don't call
getAdresseList()
inside the withContext(Dispatchers.Main)
block because this will be run on the main thread. Call it outside so it's properly dispatched by Dispatchers.Default
and use only the result on the main thread– pdegand59
Nov 14 '18 at 16:30
Don't call
getAdresseList()
inside the withContext(Dispatchers.Main)
block because this will be run on the main thread. Call it outside so it's properly dispatched by Dispatchers.Default
and use only the result on the main thread– pdegand59
Nov 14 '18 at 16:30
add a comment |
Although others have pointed out that, in this case, the library provides its own method to post an operation to the main thread, coroutines provide a general solution that works regardless of a given library's functionality.
The first step is to stop using GlobalScope
for background jobs, doing this will lead to leaks where your activity, or scheduled job, or whatever unit of work you invoke this from, may get destroyed, and yet your job will continue in the background and even submit its results to the main thread. Here's what the official documentation on GlobalScope
states:
Application code usually should use application-defined CoroutineScope, using async or launch on the instance of GlobalScope is highly discouraged.
You should define your own coroutine scope and its coroutineContext
property should contain Dispatchers.Main
as the dispatcher. Furthermore, the whole pattern of launching jobs within a function call and returning LiveData
(which is basically another kind of Future
), isn't the most convenient way to use coroutines. Instead you should have
suspend fun getAddresses() = withContext(Dispatchers.Default) { getAddressList() }
and at the call site you should launch
a coroutine, within which you can now freely call getAddresses()
as if it was a blocking method and get the addresses directly as a return value.
add a comment |
Although others have pointed out that, in this case, the library provides its own method to post an operation to the main thread, coroutines provide a general solution that works regardless of a given library's functionality.
The first step is to stop using GlobalScope
for background jobs, doing this will lead to leaks where your activity, or scheduled job, or whatever unit of work you invoke this from, may get destroyed, and yet your job will continue in the background and even submit its results to the main thread. Here's what the official documentation on GlobalScope
states:
Application code usually should use application-defined CoroutineScope, using async or launch on the instance of GlobalScope is highly discouraged.
You should define your own coroutine scope and its coroutineContext
property should contain Dispatchers.Main
as the dispatcher. Furthermore, the whole pattern of launching jobs within a function call and returning LiveData
(which is basically another kind of Future
), isn't the most convenient way to use coroutines. Instead you should have
suspend fun getAddresses() = withContext(Dispatchers.Default) { getAddressList() }
and at the call site you should launch
a coroutine, within which you can now freely call getAddresses()
as if it was a blocking method and get the addresses directly as a return value.
add a comment |
Although others have pointed out that, in this case, the library provides its own method to post an operation to the main thread, coroutines provide a general solution that works regardless of a given library's functionality.
The first step is to stop using GlobalScope
for background jobs, doing this will lead to leaks where your activity, or scheduled job, or whatever unit of work you invoke this from, may get destroyed, and yet your job will continue in the background and even submit its results to the main thread. Here's what the official documentation on GlobalScope
states:
Application code usually should use application-defined CoroutineScope, using async or launch on the instance of GlobalScope is highly discouraged.
You should define your own coroutine scope and its coroutineContext
property should contain Dispatchers.Main
as the dispatcher. Furthermore, the whole pattern of launching jobs within a function call and returning LiveData
(which is basically another kind of Future
), isn't the most convenient way to use coroutines. Instead you should have
suspend fun getAddresses() = withContext(Dispatchers.Default) { getAddressList() }
and at the call site you should launch
a coroutine, within which you can now freely call getAddresses()
as if it was a blocking method and get the addresses directly as a return value.
Although others have pointed out that, in this case, the library provides its own method to post an operation to the main thread, coroutines provide a general solution that works regardless of a given library's functionality.
The first step is to stop using GlobalScope
for background jobs, doing this will lead to leaks where your activity, or scheduled job, or whatever unit of work you invoke this from, may get destroyed, and yet your job will continue in the background and even submit its results to the main thread. Here's what the official documentation on GlobalScope
states:
Application code usually should use application-defined CoroutineScope, using async or launch on the instance of GlobalScope is highly discouraged.
You should define your own coroutine scope and its coroutineContext
property should contain Dispatchers.Main
as the dispatcher. Furthermore, the whole pattern of launching jobs within a function call and returning LiveData
(which is basically another kind of Future
), isn't the most convenient way to use coroutines. Instead you should have
suspend fun getAddresses() = withContext(Dispatchers.Default) { getAddressList() }
and at the call site you should launch
a coroutine, within which you can now freely call getAddresses()
as if it was a blocking method and get the addresses directly as a return value.
answered Nov 15 '18 at 10:13
Marko TopolnikMarko Topolnik
147k19198323
147k19198323
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53304347%2fmutablelivedata-cannot-invoke-setvalue-on-a-background-thread-from-coroutine%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Is there a reason you don't want to use postValue?
– RedDeckWins
Nov 14 '18 at 16:28
@RedDeckWins. No, I just didn't take it into account but it is definitely the way to update MutableLiveData from a coroutine.
– kike
Nov 15 '18 at 8:31