zasaz
zasaz

Reputation: 2524

Coroutine calling API Android

I have to call an API asynchronously. To do it i'm using a coroutine, but i have to wait until the API is called to load the data. The problem is the next:

The await is not working as I want, it's not waiting until the API gives all the data.

Is the await what I need? Here is the code:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_see)
    launch { loaddata() }
    /* some other code here*/
}

suspend fun loadData(){
    val readData = async { read() }
    readData.join()
    readData.await()
    val showScreen = async { refreshList() }
    showScreen.join()
    showScreen.await()
}


fun read(){
    val stringRequest = object : StringRequest(Request.Method.POST, URL, Response.Listener<String>{ s ->
        try {
                val array = JSONArray(s)
                for (i in 0..array.length() - 1) {
                    val objectAccount = array.getJSONObject(i)
                    val account = Account(
                            objectAccount.getString(value),
                            objectAccount.getString(value),
                            objectAccount.getString(value))
                    listAccount.add(account)
                }
        }catch (e: JSONException){
            e.printStackTrace()
        }
    }, Response.ErrorListener { error: VolleyError? -> Log.e("error", "error")  }){
        override fun getParams(): Map<String, String> {
            val params = HashMap<String, String>()
            params.put("password", value)
            params.put("idaccount", value)
            return params
        }
    }
    val  requesQueue = Volley.newRequestQueue(this)
    requesQueue.add<String>(stringRequest)
}

Upvotes: 2

Views: 1709

Answers (1)

garywzh
garywzh

Reputation: 550

Usually you shouldn't call a async function

requesQueue.add<String>(stringRequest)

in the async coroutine builder

async {}

Sulution #1

you can change your read() method to a synchronous request. Can I do a synchronous request with volley? and run it with CommonPool

async(CommonPool) {
    read()
}

Solution #2

wrap your async http call into a suspend function

I am NOT familiar with Volley, so maybe the code needs tweak

suspend fun read() {
    return suspendCancellableCoroutine { continuation ->

        val stringRequest = object : StringRequest(Request.Method.POST, URL, Response.Listener<String> { s ->
            try {
                val array = JSONArray(s)
                for (i in 0..array.length() - 1) {
                    val objectAccount = array.getJSONObject(i)
                    val account = Account(
                            objectAccount.getString(value),
                            objectAccount.getString(value),
                            objectAccount.getString(value))
                    listAccount.add(account)
                }
            } catch (e: JSONException) {
                e.printStackTrace()

                // notice this
                continuation.resumeWithException(e)
            }
            // notice this
            continuation.resume()

        }, Response.ErrorListener { error: VolleyError? ->
            Log.e("error", "error")

            // notice this
            if (!continuation.isCancelled)
                continuation.resumeWithException()

        }) {
            override fun getParams(): Map<String, String> {
                val params = HashMap<String, String>()
                params.put("password", value)
                params.put("idaccount", value)
                return params
            }
        }

        val requesQueue = Volley.newRequestQueue(this)
        requesQueue.add<String>(stringRequest)

        continuation.invokeOnCompletion {
            if (continuation.isCancelled)
                try {
                    cancel()
                } catch (ex: Throwable) {
                    //Ignore cancel exception
                }
        }
    }
}

and call it like this

suspend fun loadData(){

    read()

    val showScreen = async { refreshList() }
    showScreen.join()
    showScreen.await()
}

Upvotes: 1

Related Questions