MutableLiveData: Cannot invoke setValue on a background thread from Coroutine












1















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?










share|improve this question


















  • 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















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?










share|improve this question


















  • 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








1








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?










share|improve this question














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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










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














  • 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












3 Answers
3






active

oldest

votes


















1














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
}





share|improve this answer
























  • 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



















0














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
}





share|improve this answer



















  • 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





















0














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.






share|improve this answer























    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
    });


    }
    });














    draft saved

    draft discarded


















    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









    1














    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
    }





    share|improve this answer
























    • 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
















    1














    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
    }





    share|improve this answer
























    • 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














    1












    1








    1







    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
    }





    share|improve this answer













    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
    }






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 14 '18 at 16:28









    pdegand59pdegand59

    7,10073447




    7,10073447













    • 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

















    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













    0














    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
    }





    share|improve this answer



















    • 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


















    0














    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
    }





    share|improve this answer



















    • 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
















    0












    0








    0







    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
    }





    share|improve this answer













    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
    }






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 14 '18 at 16:20









    kikekike

    804727




    804727








    • 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
















    • 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










    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













    0














    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.






    share|improve this answer




























      0














      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.






      share|improve this answer


























        0












        0








        0







        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.






        share|improve this answer













        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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 15 '18 at 10:13









        Marko TopolnikMarko Topolnik

        147k19198323




        147k19198323






























            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            Bressuire

            Vorschmack

            Quarantine