AndroidNetworking never returns when in suspendCoroutine in Kotlin












0















I am experimenting with the new coroutines and trying to incorporate them into an existing project with some ugly AndroidNetworking api requests.



So my current api requests are using callbacks like this...



fun getSomethingFromBackend(callback: (response: JSONArray?, error: String?) -> Unit) {
AndroidNetworking.get(...).build().getAsJSONObject(object : JSONObjectRequestListener {
override fun onResponse(response: JSONObject) { ... }
override fun onError(error: ANError) { ... }
}
}


And now I am trying to incorporate coroutines like this...



fun someFunction() = runBlocking {
async { callGetSomething() }.await()
}

suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
Something().getSomethingFromBackend {something
...
it.resume(something)
}
}


As you can see, I am trying to run the callGetSomething in a coroutine and once there, suspend the coroutine until the async API returns.



My problem is, it never returns. Even if I debug in the onResponse, onError, etc, it never get back from the backend.



But if I remove the = suspendCoroutine it works, at least it returns, but the await will not work off corse, because the execution will just continue.



How can I solve this so the await() actually waits for the async call callback?



Thanks a lot!










share|improve this question























  • are you sure getSomethingFromBackend callback is always invoked?

    – qwwdfsad
    Nov 16 '18 at 9:35








  • 1





    also, if someFunction and callback should be invoked from the same thread, then it won't happen, because you blocked it with runBlocking

    – qwwdfsad
    Nov 16 '18 at 9:36
















0















I am experimenting with the new coroutines and trying to incorporate them into an existing project with some ugly AndroidNetworking api requests.



So my current api requests are using callbacks like this...



fun getSomethingFromBackend(callback: (response: JSONArray?, error: String?) -> Unit) {
AndroidNetworking.get(...).build().getAsJSONObject(object : JSONObjectRequestListener {
override fun onResponse(response: JSONObject) { ... }
override fun onError(error: ANError) { ... }
}
}


And now I am trying to incorporate coroutines like this...



fun someFunction() = runBlocking {
async { callGetSomething() }.await()
}

suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
Something().getSomethingFromBackend {something
...
it.resume(something)
}
}


As you can see, I am trying to run the callGetSomething in a coroutine and once there, suspend the coroutine until the async API returns.



My problem is, it never returns. Even if I debug in the onResponse, onError, etc, it never get back from the backend.



But if I remove the = suspendCoroutine it works, at least it returns, but the await will not work off corse, because the execution will just continue.



How can I solve this so the await() actually waits for the async call callback?



Thanks a lot!










share|improve this question























  • are you sure getSomethingFromBackend callback is always invoked?

    – qwwdfsad
    Nov 16 '18 at 9:35








  • 1





    also, if someFunction and callback should be invoked from the same thread, then it won't happen, because you blocked it with runBlocking

    – qwwdfsad
    Nov 16 '18 at 9:36














0












0








0








I am experimenting with the new coroutines and trying to incorporate them into an existing project with some ugly AndroidNetworking api requests.



So my current api requests are using callbacks like this...



fun getSomethingFromBackend(callback: (response: JSONArray?, error: String?) -> Unit) {
AndroidNetworking.get(...).build().getAsJSONObject(object : JSONObjectRequestListener {
override fun onResponse(response: JSONObject) { ... }
override fun onError(error: ANError) { ... }
}
}


And now I am trying to incorporate coroutines like this...



fun someFunction() = runBlocking {
async { callGetSomething() }.await()
}

suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
Something().getSomethingFromBackend {something
...
it.resume(something)
}
}


As you can see, I am trying to run the callGetSomething in a coroutine and once there, suspend the coroutine until the async API returns.



My problem is, it never returns. Even if I debug in the onResponse, onError, etc, it never get back from the backend.



But if I remove the = suspendCoroutine it works, at least it returns, but the await will not work off corse, because the execution will just continue.



How can I solve this so the await() actually waits for the async call callback?



Thanks a lot!










share|improve this question














I am experimenting with the new coroutines and trying to incorporate them into an existing project with some ugly AndroidNetworking api requests.



So my current api requests are using callbacks like this...



fun getSomethingFromBackend(callback: (response: JSONArray?, error: String?) -> Unit) {
AndroidNetworking.get(...).build().getAsJSONObject(object : JSONObjectRequestListener {
override fun onResponse(response: JSONObject) { ... }
override fun onError(error: ANError) { ... }
}
}


And now I am trying to incorporate coroutines like this...



fun someFunction() = runBlocking {
async { callGetSomething() }.await()
}

suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
Something().getSomethingFromBackend {something
...
it.resume(something)
}
}


As you can see, I am trying to run the callGetSomething in a coroutine and once there, suspend the coroutine until the async API returns.



My problem is, it never returns. Even if I debug in the onResponse, onError, etc, it never get back from the backend.



But if I remove the = suspendCoroutine it works, at least it returns, but the await will not work off corse, because the execution will just continue.



How can I solve this so the await() actually waits for the async call callback?



Thanks a lot!







android kotlin coroutine kotlinx.coroutines






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 15 '18 at 19:47









Eduardo Oviedo BlancoEduardo Oviedo Blanco

95




95













  • are you sure getSomethingFromBackend callback is always invoked?

    – qwwdfsad
    Nov 16 '18 at 9:35








  • 1





    also, if someFunction and callback should be invoked from the same thread, then it won't happen, because you blocked it with runBlocking

    – qwwdfsad
    Nov 16 '18 at 9:36



















  • are you sure getSomethingFromBackend callback is always invoked?

    – qwwdfsad
    Nov 16 '18 at 9:35








  • 1





    also, if someFunction and callback should be invoked from the same thread, then it won't happen, because you blocked it with runBlocking

    – qwwdfsad
    Nov 16 '18 at 9:36

















are you sure getSomethingFromBackend callback is always invoked?

– qwwdfsad
Nov 16 '18 at 9:35







are you sure getSomethingFromBackend callback is always invoked?

– qwwdfsad
Nov 16 '18 at 9:35






1




1





also, if someFunction and callback should be invoked from the same thread, then it won't happen, because you blocked it with runBlocking

– qwwdfsad
Nov 16 '18 at 9:36





also, if someFunction and callback should be invoked from the same thread, then it won't happen, because you blocked it with runBlocking

– qwwdfsad
Nov 16 '18 at 9:36












3 Answers
3






active

oldest

votes


















1














Ok, thank you all for your help.
I'll explain how I found the problem and how I was able to solve it.



After studying more about callbacks and coroutines I decided to log the thread name during the call back, like this. Log.d("TAG", "Execution thread: "+Thread.currentThread().name).



This lead me to the realization that all the call backs (error and success), where actually running on the main thread, and NOT on the coroutine I set for it.



So the code in my coroutine runs in D/TAG: Execution thread: DefaultDispatcher-worker-1 but the callbacks runs on D/TAG: Execution thread: main.



The solution




  1. Avoid runBlocking: This will block the main thread, and in this case this was the reason for the callbacks never returning.


  2. Use the Dispatchers.Main when starting the coroutine, so I can actually use the returned values in the UI.


  3. Use a suspendCoroutine with it's resume() and resumeWithException (Thanks @Sergey)



Example



fun someFunction() {
GlobalScope.launch(Dispatchers.Main) {
result = GlobalScope.async { callGetSomething() }.await()
...
}
}

suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
Something().getSomethingFromBackend {something
...
it.resume(something)
}
}





share|improve this answer































    0














    try something like this:



    fun someFunction() {
    val jsonObject: JSONObject? = runBlocking {
    callGetSomething()
    }
    // do something with jsonObject
    }

    suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
    Something().getSomethingFromBackend { response, error ->
    it.resume(response)
    }
    }





    share|improve this answer
























    • Thanks @Sergey but it's not working, the AndroidNetworking.get is being called, the coroutine is waiting, but the callback never gets called. No response, no error, nothing...

      – Eduardo Oviedo Blanco
      Nov 15 '18 at 20:39



















    0














    Your main problem is that you're trying to use runBlocking, which cancels out all the work you did to introduce an async networking library and coroutines to your project. If you really want to block while waiting for the results, then just use blocking network calls.



    If you want to continue using async network ops, then forget about your blocking someFunction and directly use callGetSomething from a launch block:



    override fun onSomeEvent(...) {
    this.launch {
    val result = callGetSomething(...)
    // use the result, you're on the GUI thread here
    }
    }


    The above assumes your this is an Activity, Fragment, ViewModel or a similar object that implements CoroutineScope. See its documentation to see how to achieve that.






    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%2f53326917%2fandroidnetworking-never-returns-when-in-suspendcoroutine-in-kotlin%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














      Ok, thank you all for your help.
      I'll explain how I found the problem and how I was able to solve it.



      After studying more about callbacks and coroutines I decided to log the thread name during the call back, like this. Log.d("TAG", "Execution thread: "+Thread.currentThread().name).



      This lead me to the realization that all the call backs (error and success), where actually running on the main thread, and NOT on the coroutine I set for it.



      So the code in my coroutine runs in D/TAG: Execution thread: DefaultDispatcher-worker-1 but the callbacks runs on D/TAG: Execution thread: main.



      The solution




      1. Avoid runBlocking: This will block the main thread, and in this case this was the reason for the callbacks never returning.


      2. Use the Dispatchers.Main when starting the coroutine, so I can actually use the returned values in the UI.


      3. Use a suspendCoroutine with it's resume() and resumeWithException (Thanks @Sergey)



      Example



      fun someFunction() {
      GlobalScope.launch(Dispatchers.Main) {
      result = GlobalScope.async { callGetSomething() }.await()
      ...
      }
      }

      suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
      Something().getSomethingFromBackend {something
      ...
      it.resume(something)
      }
      }





      share|improve this answer




























        1














        Ok, thank you all for your help.
        I'll explain how I found the problem and how I was able to solve it.



        After studying more about callbacks and coroutines I decided to log the thread name during the call back, like this. Log.d("TAG", "Execution thread: "+Thread.currentThread().name).



        This lead me to the realization that all the call backs (error and success), where actually running on the main thread, and NOT on the coroutine I set for it.



        So the code in my coroutine runs in D/TAG: Execution thread: DefaultDispatcher-worker-1 but the callbacks runs on D/TAG: Execution thread: main.



        The solution




        1. Avoid runBlocking: This will block the main thread, and in this case this was the reason for the callbacks never returning.


        2. Use the Dispatchers.Main when starting the coroutine, so I can actually use the returned values in the UI.


        3. Use a suspendCoroutine with it's resume() and resumeWithException (Thanks @Sergey)



        Example



        fun someFunction() {
        GlobalScope.launch(Dispatchers.Main) {
        result = GlobalScope.async { callGetSomething() }.await()
        ...
        }
        }

        suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
        Something().getSomethingFromBackend {something
        ...
        it.resume(something)
        }
        }





        share|improve this answer


























          1












          1








          1







          Ok, thank you all for your help.
          I'll explain how I found the problem and how I was able to solve it.



          After studying more about callbacks and coroutines I decided to log the thread name during the call back, like this. Log.d("TAG", "Execution thread: "+Thread.currentThread().name).



          This lead me to the realization that all the call backs (error and success), where actually running on the main thread, and NOT on the coroutine I set for it.



          So the code in my coroutine runs in D/TAG: Execution thread: DefaultDispatcher-worker-1 but the callbacks runs on D/TAG: Execution thread: main.



          The solution




          1. Avoid runBlocking: This will block the main thread, and in this case this was the reason for the callbacks never returning.


          2. Use the Dispatchers.Main when starting the coroutine, so I can actually use the returned values in the UI.


          3. Use a suspendCoroutine with it's resume() and resumeWithException (Thanks @Sergey)



          Example



          fun someFunction() {
          GlobalScope.launch(Dispatchers.Main) {
          result = GlobalScope.async { callGetSomething() }.await()
          ...
          }
          }

          suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
          Something().getSomethingFromBackend {something
          ...
          it.resume(something)
          }
          }





          share|improve this answer













          Ok, thank you all for your help.
          I'll explain how I found the problem and how I was able to solve it.



          After studying more about callbacks and coroutines I decided to log the thread name during the call back, like this. Log.d("TAG", "Execution thread: "+Thread.currentThread().name).



          This lead me to the realization that all the call backs (error and success), where actually running on the main thread, and NOT on the coroutine I set for it.



          So the code in my coroutine runs in D/TAG: Execution thread: DefaultDispatcher-worker-1 but the callbacks runs on D/TAG: Execution thread: main.



          The solution




          1. Avoid runBlocking: This will block the main thread, and in this case this was the reason for the callbacks never returning.


          2. Use the Dispatchers.Main when starting the coroutine, so I can actually use the returned values in the UI.


          3. Use a suspendCoroutine with it's resume() and resumeWithException (Thanks @Sergey)



          Example



          fun someFunction() {
          GlobalScope.launch(Dispatchers.Main) {
          result = GlobalScope.async { callGetSomething() }.await()
          ...
          }
          }

          suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
          Something().getSomethingFromBackend {something
          ...
          it.resume(something)
          }
          }






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 24 at 5:35









          Eduardo Oviedo BlancoEduardo Oviedo Blanco

          95




          95

























              0














              try something like this:



              fun someFunction() {
              val jsonObject: JSONObject? = runBlocking {
              callGetSomething()
              }
              // do something with jsonObject
              }

              suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
              Something().getSomethingFromBackend { response, error ->
              it.resume(response)
              }
              }





              share|improve this answer
























              • Thanks @Sergey but it's not working, the AndroidNetworking.get is being called, the coroutine is waiting, but the callback never gets called. No response, no error, nothing...

                – Eduardo Oviedo Blanco
                Nov 15 '18 at 20:39
















              0














              try something like this:



              fun someFunction() {
              val jsonObject: JSONObject? = runBlocking {
              callGetSomething()
              }
              // do something with jsonObject
              }

              suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
              Something().getSomethingFromBackend { response, error ->
              it.resume(response)
              }
              }





              share|improve this answer
























              • Thanks @Sergey but it's not working, the AndroidNetworking.get is being called, the coroutine is waiting, but the callback never gets called. No response, no error, nothing...

                – Eduardo Oviedo Blanco
                Nov 15 '18 at 20:39














              0












              0








              0







              try something like this:



              fun someFunction() {
              val jsonObject: JSONObject? = runBlocking {
              callGetSomething()
              }
              // do something with jsonObject
              }

              suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
              Something().getSomethingFromBackend { response, error ->
              it.resume(response)
              }
              }





              share|improve this answer













              try something like this:



              fun someFunction() {
              val jsonObject: JSONObject? = runBlocking {
              callGetSomething()
              }
              // do something with jsonObject
              }

              suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
              Something().getSomethingFromBackend { response, error ->
              it.resume(response)
              }
              }






              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Nov 15 '18 at 20:21









              SergeySergey

              4,21421835




              4,21421835













              • Thanks @Sergey but it's not working, the AndroidNetworking.get is being called, the coroutine is waiting, but the callback never gets called. No response, no error, nothing...

                – Eduardo Oviedo Blanco
                Nov 15 '18 at 20:39



















              • Thanks @Sergey but it's not working, the AndroidNetworking.get is being called, the coroutine is waiting, but the callback never gets called. No response, no error, nothing...

                – Eduardo Oviedo Blanco
                Nov 15 '18 at 20:39

















              Thanks @Sergey but it's not working, the AndroidNetworking.get is being called, the coroutine is waiting, but the callback never gets called. No response, no error, nothing...

              – Eduardo Oviedo Blanco
              Nov 15 '18 at 20:39





              Thanks @Sergey but it's not working, the AndroidNetworking.get is being called, the coroutine is waiting, but the callback never gets called. No response, no error, nothing...

              – Eduardo Oviedo Blanco
              Nov 15 '18 at 20:39











              0














              Your main problem is that you're trying to use runBlocking, which cancels out all the work you did to introduce an async networking library and coroutines to your project. If you really want to block while waiting for the results, then just use blocking network calls.



              If you want to continue using async network ops, then forget about your blocking someFunction and directly use callGetSomething from a launch block:



              override fun onSomeEvent(...) {
              this.launch {
              val result = callGetSomething(...)
              // use the result, you're on the GUI thread here
              }
              }


              The above assumes your this is an Activity, Fragment, ViewModel or a similar object that implements CoroutineScope. See its documentation to see how to achieve that.






              share|improve this answer




























                0














                Your main problem is that you're trying to use runBlocking, which cancels out all the work you did to introduce an async networking library and coroutines to your project. If you really want to block while waiting for the results, then just use blocking network calls.



                If you want to continue using async network ops, then forget about your blocking someFunction and directly use callGetSomething from a launch block:



                override fun onSomeEvent(...) {
                this.launch {
                val result = callGetSomething(...)
                // use the result, you're on the GUI thread here
                }
                }


                The above assumes your this is an Activity, Fragment, ViewModel or a similar object that implements CoroutineScope. See its documentation to see how to achieve that.






                share|improve this answer


























                  0












                  0








                  0







                  Your main problem is that you're trying to use runBlocking, which cancels out all the work you did to introduce an async networking library and coroutines to your project. If you really want to block while waiting for the results, then just use blocking network calls.



                  If you want to continue using async network ops, then forget about your blocking someFunction and directly use callGetSomething from a launch block:



                  override fun onSomeEvent(...) {
                  this.launch {
                  val result = callGetSomething(...)
                  // use the result, you're on the GUI thread here
                  }
                  }


                  The above assumes your this is an Activity, Fragment, ViewModel or a similar object that implements CoroutineScope. See its documentation to see how to achieve that.






                  share|improve this answer













                  Your main problem is that you're trying to use runBlocking, which cancels out all the work you did to introduce an async networking library and coroutines to your project. If you really want to block while waiting for the results, then just use blocking network calls.



                  If you want to continue using async network ops, then forget about your blocking someFunction and directly use callGetSomething from a launch block:



                  override fun onSomeEvent(...) {
                  this.launch {
                  val result = callGetSomething(...)
                  // use the result, you're on the GUI thread here
                  }
                  }


                  The above assumes your this is an Activity, Fragment, ViewModel or a similar object that implements CoroutineScope. See its documentation to see how to achieve that.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 19 '18 at 7:26









                  Marko TopolnikMarko Topolnik

                  148k19199328




                  148k19199328






























                      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%2f53326917%2fandroidnetworking-never-returns-when-in-suspendcoroutine-in-kotlin%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

                      Xamarin.iOS Cant Deploy on Iphone

                      Glorious Revolution

                      Dulmage-Mendelsohn matrix decomposition in Python