AndroidNetworking never returns when in suspendCoroutine in Kotlin
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
add a comment |
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
are you suregetSomethingFromBackend
callback is always invoked?
– qwwdfsad
Nov 16 '18 at 9:35
1
also, ifsomeFunction
and callback should be invoked from the same thread, then it won't happen, because you blocked it withrunBlocking
– qwwdfsad
Nov 16 '18 at 9:36
add a comment |
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
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
android kotlin coroutine kotlinx.coroutines
asked Nov 15 '18 at 19:47
Eduardo Oviedo BlancoEduardo Oviedo Blanco
95
95
are you suregetSomethingFromBackend
callback is always invoked?
– qwwdfsad
Nov 16 '18 at 9:35
1
also, ifsomeFunction
and callback should be invoked from the same thread, then it won't happen, because you blocked it withrunBlocking
– qwwdfsad
Nov 16 '18 at 9:36
add a comment |
are you suregetSomethingFromBackend
callback is always invoked?
– qwwdfsad
Nov 16 '18 at 9:35
1
also, ifsomeFunction
and callback should be invoked from the same thread, then it won't happen, because you blocked it withrunBlocking
– 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
add a comment |
3 Answers
3
active
oldest
votes
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
Avoid
runBlocking
: This will block the main thread, and in this case this was the reason for the callbacks never returning.Use the
Dispatchers.Main
when starting the coroutine, so I can actually use the returned values in the UI.Use a
suspendCoroutine
with it'sresume()
andresumeWithException
(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)
}
}
add a comment |
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)
}
}
Thanks @Sergey but it's not working, theAndroidNetworking.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
add a comment |
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.
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%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
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
Avoid
runBlocking
: This will block the main thread, and in this case this was the reason for the callbacks never returning.Use the
Dispatchers.Main
when starting the coroutine, so I can actually use the returned values in the UI.Use a
suspendCoroutine
with it'sresume()
andresumeWithException
(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)
}
}
add a comment |
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
Avoid
runBlocking
: This will block the main thread, and in this case this was the reason for the callbacks never returning.Use the
Dispatchers.Main
when starting the coroutine, so I can actually use the returned values in the UI.Use a
suspendCoroutine
with it'sresume()
andresumeWithException
(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)
}
}
add a comment |
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
Avoid
runBlocking
: This will block the main thread, and in this case this was the reason for the callbacks never returning.Use the
Dispatchers.Main
when starting the coroutine, so I can actually use the returned values in the UI.Use a
suspendCoroutine
with it'sresume()
andresumeWithException
(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)
}
}
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
Avoid
runBlocking
: This will block the main thread, and in this case this was the reason for the callbacks never returning.Use the
Dispatchers.Main
when starting the coroutine, so I can actually use the returned values in the UI.Use a
suspendCoroutine
with it'sresume()
andresumeWithException
(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)
}
}
answered Jan 24 at 5:35
Eduardo Oviedo BlancoEduardo Oviedo Blanco
95
95
add a comment |
add a comment |
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)
}
}
Thanks @Sergey but it's not working, theAndroidNetworking.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
add a comment |
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)
}
}
Thanks @Sergey but it's not working, theAndroidNetworking.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
add a comment |
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)
}
}
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)
}
}
answered Nov 15 '18 at 20:21
SergeySergey
4,21421835
4,21421835
Thanks @Sergey but it's not working, theAndroidNetworking.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
add a comment |
Thanks @Sergey but it's not working, theAndroidNetworking.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
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered Nov 19 '18 at 7:26
Marko TopolnikMarko Topolnik
148k19199328
148k19199328
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%2f53326917%2fandroidnetworking-never-returns-when-in-suspendcoroutine-in-kotlin%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
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 withrunBlocking
– qwwdfsad
Nov 16 '18 at 9:36