0

My project has a lot of operations that must be performed one after another. I was using listeners, but I found this tutorial Kotlin coroutines on Android and I wanted to change my sever call with better readable code. But I think I am missing something. The below code always return an error from getTime1() function:

suspend fun getTimeFromServer1() :ResultServer<Long> {
        val userId = SharedPrefsHelper.getClientId()
        return withContext(Dispatchers.IO) {
            val call: Call<ResponseFromServer>? = userId?.let { apiInterface.getTime(it) }
            (call?.execute()?.body())?.run {
                val time:Long? = this.data?.time
                time?.let {
                    Timber.tag("xxx").e("time received it ${it}")// I am getting the right result here
                    ResultServer.Success(it)
                }
                Timber.tag("xxx").e("time received ${time}")
            }
            ResultServer.Error(Exception("Cannot get time"))
        }
    }


fun getTime1() {
        GlobalScope.launch {
            when (val expr: ResultServer<Long> = NetworkLayer.getTimeFromServer1()) {
                is ResultServer.Success<Long> -> Timber.tag("xxx").e("time is ${expr.data}")
                is ResultServer.Error -> Timber.tag("xxx").e("time Error") //I am always get here
            }}
    }
    }

But if I am using listeners (getTime()) everything works perfectly:

 suspend fun getTimeFromServer(savingFinishedListener: SavingFinishedListener<Long>) {
        val userId = SharedPrefsHelper.getClientId()
        withContext(Dispatchers.IO) {
            val call: Call<ResponseFromServer>? = userId?.let { apiInterface.getTime(it) }
            (call?.execute()?.body())?.run {
                val time:Long? = this.data?.time
                time?.let {
                    Timber.tag("xxx").e("time received it ${it}")
                    savingFinishedListener.onSuccess(it)
                }

            }
            savingFinishedListener.onSuccess(null)
        }
    }

   fun getTime() {
        GlobalScope.launch {
            NetworkLayer.getTimeFromServer(object:SavingFinishedListener<Long>{
                override fun onSuccess(t: Long?) {
                    t?.let {
                        Timber.tag("xxx").e("time here $it") //I am getting the right result
                    }
                }
            })
           }
        }

Thanks in advance for any help.

KeitL
  • 188
  • 2
  • 13

1 Answers1

1

The last line of a lambda is implicitly the return value of that lambda. Since you don't have any explicit return statements in your withContext lambda, its last line:

ResultServer.Error(Exception("Cannot get time"))

means that it always returns this Error. You can put return@withContext right before your ResultServer.Success(it) to make that line of code also return from the lambda.

Side note: don't use GlobalScope.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • Thanks a lot. It works. But that context I suppose to use? – KeitL Jan 29 '21 at 19:34
  • Android provides lifecycle scopes for Activities/Fragments and ViewModels (called `lifecycleScope` and `viewModelScope` respectively), and these are useful for most cases. They automatically get cancelled when the related lifecycle is over. If you need more control over cancellation, then you create your own coroutine scope using `CoroutineScope()`. – Tenfour04 Jan 29 '21 at 19:42
  • By the way, if you're using Retrofit, you can remove the `withContext()` wrapper and use `await()` instead of `execute()`. `await()` is a suspending version of `execute()`. – Tenfour04 Jan 29 '21 at 19:45
  • I rewrited it a little bit. But now I am getting error: A 'return' expression required in a function with a block body ('{...}'). – KeitL Jan 29 '21 at 19:52
  • suspend fun getTimeFromServer3() : ResultServer? { val userId = SharedPrefsHelper.getClientId() val call: Call? = userId?.let { apiInterface.getTime(it) } (call?.await())?.run { return when(val time:Long? = this.data?.time){ is Long -> ResultServer.Success(time) else -> ResultServer.Error(java.lang.Exception("ndndndn")) } } } – KeitL Jan 29 '21 at 19:53
  • You've removed `withContext`, but you've also removed your `return` keyword. You have to explicitly use the `return` keyword on the lines where you are returning something. – Tenfour04 Jan 29 '21 at 20:03