call a suspend function inside a normal function
Asked Answered
T

1

32

I want to call blocking a suspend function in a normal function, but does not block Thread to finishing suspend function and then return Response

override fun intercept(chain: Interceptor.Chain): Response {

    // getSession is a suspend function
    val session = sessionProvider.getSession()

    return chain.proceed(
        chain
            .request()
            .newBuilder()
            .addHeader("Authorization", "${session.token}")
            .build()
    )
}
Tace answered 1/6, 2019 at 19:52 Comment(1)
You need to block the thread if you want to return value from your function. If you don't want to block you need to use callback function.Catadromous
N
67

This looks like you are implementing an OkHttp interceptor, so I am hoping that intercept() is being called on a background thread.

If so, use runBlocking():

override fun intercept(chain: Interceptor.Chain): Response {

    // getSession is a suspend function
    val session = runBlocking { sessionProvider.getSession() }

    return chain.proceed(
        chain
            .request()
            .newBuilder()
            .addHeader("Authorization", "${session.token}")
            .build()
    )
}

runBlocking() will execute the suspend function, blocking the current thread until that work is complete.

Nosing answered 1/6, 2019 at 19:56 Comment(10)
Would this cause issues because the return will be delayed and the intercept function is not marked as a suspend function?Faubourg
@3366784: runBlocking() is not itself an suspend function, so from a compilation standpoint, everything should be fine. How well this works at runtime depends a lot on how well-behaved sessionProvider.getSession() is. If that takes a long time, every OkHttp request will take a long time, because the runBlocking() call is a blocking call, and intercept() will not proceed until runBlocking() completes.Nosing
Okay I understand it depends on .getSession(). I was confused because I know there are some languages that will kill your app if a regular function with return value take more than x seconds to return. But in this situation we are forced to delay the return and as you said this is okay. I tested this and added an extra delay and it didn't block the UI thread and didn't crash therefore it should be good.Faubourg
@Faubourg "languages that will kill your app if a regular function with return value take more than x seconds to return" - could you provide examples? I've never heard of that kind of language feature.Lineal
yeah Retrofit by default should run suspend api methods on its predefined background io dispatcherHowerton
i don't think that we should used runBlocking in production app this is used for testing the app only.Owlet
@karan: I agree, it is the sort of thing that you should avoid where you can. However, in this case, until and unless OkHttp interceptors start to support suspend fun directly, you have little practical choice.Nosing
to avoid runBlocking i have used CountDownLatch Example:- GlobalScope.launch(Dispatchers.IO){ request = getToken(chain) countDownLatch.countDown() } try { countDownLatch.await(2000,TimeUnit.SECONDS) }catch (_:Exception){ }Owlet
@karan: If your objective was the timeout, withTimeout() inside runBlocking() would be simpler.Nosing
@Nosing my Objective is not to use runBlocking instead you can use CountDownLatchOwlet

© 2022 - 2024 — McMap. All rights reserved.