Android(Kotlin) - 如何等待异步任务完成?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android(Kotlin) - 如何等待异步任务完成?相关的知识,希望对你有一定的参考价值。

我是android和Kotlin的新手,目前正在开发集中式API路由器类。为了达到这个目的,我使用的是Fuel Framework。对于doAsync函数,我使用Anko for Kotlin库。

要从API检索授权令牌,我目前使用此方法:

 private fun Login(username: String, password: String, callback: (Map<Boolean, String>) -> Unit) {

        "/auth/token.json".httpPost()
                .header(mapOf("Content-Type" to "application/json"))
                .body("""{"username":"$username", "password":"$password"}""", Charsets.UTF_8)
                .response { request, response, result ->
                    request.headers.remove("Accept-Encoding")
                    when (result) {
                        is Result.Failure -> {

                            // val data = result.get()
                            val ex = result.getException()
                            val serverResponseJson = response.data.toString(Charsets.UTF_8)
                            var exceptionMessage = ex.message

                            val jelement = JsonParser().parse(serverResponseJson)
                            val jobject = jelement.asJsonObject

                            val serverResponseError = if (jobject.has("Error")) jobject.get("Error").asString else jobject.get("detail").asString


                            callback(mapOf(Pair(false, serverResponseError)))
                        }
                        is Result.Success -> {
                            val data = result.get()
                            val returnJson = data.toString(Charsets.UTF_8)
                            Log.println(Log.ASSERT, "RESULT_LOGIN", returnJson)

                            callback(mapOf(Pair(true, returnJson)))
                        }
                    }


                }
    }

我在这里调用这个登录方法

val btnLogin = findViewById<Button>(R.id.btn_login)
    btnLogin.setOnClickListener { _ ->

        doAsync {
            val username = findViewById<EditText>(R.id.input_username_login)
            val password = findViewById<EditText>(R.id.input_password_login)

            Login(username.text.toString(), password.text.toString()) {

                // Request was successful
                if (it.containsKey(true)) {
                    // Parse return Json
                    // e.g. {"id":"36e8fac0-487a-11e8-ad4e-c471feb11e42","token":"d6897a230fd7739e601649bf5fd89ea4b93317f6","expiry":"2018-04-27T17:49:48.721278Z"}
                    val jelement = JsonParser().parse(it.getValue(true))
                    val jobject = jelement.asJsonObject

                    // save field for class-scope access
                    Constants.token = jobject.get("token").asString
                    Constants.id = jobject.get("id").asString
                }
                else{
                    Toast.makeText(this@LoginActivity, it.getValue(false), Toast.LENGTH_SHORT).show()
                }
            }
        }[30, TimeUnit.SECONDS]

         var test = Constants.id;

    }

在一个单独的Constants类中,我存储令牌和id,如下所示:

class Constants {
    companion object {
        val baseUrl: String = "BASE_URL_TO_MY_API"

        val contentTypeJson = "application/json"

        lateinit var STOREAGE_PATH: String

        // current user details
        lateinit var id: String
        lateinit var token: String
        lateinit var refresh_token: String

        // logged in User
        lateinit var user: User
    }

如何在异步任务完成后确保设置测试变量?目前,我遇到了

lateinit属性id尚未初始化

我遇到了将任务限制为超时的选项,例如我使用[30,TimeUnit.SECONDS],不幸的是,这没有帮助。

谢谢您的帮助!干杯。

答案

我认为问题是你想要访问结果的地方:

val btnLogin = findViewById<Button>(R.id.btn_login)
btnLogin.setOnClickListener { _ ->

       doAsync {
        val username = findViewById<EditText>(R.id.input_username_login)
        val password = findViewById<EditText>(R.id.input_password_login)

        var test: String? = null

        Login(username.text.toString(), password.text.toString()) {

            // Request was successful
            if (it.containsKey(true)) {
                // Parse return Json
                // e.g. {"id":"36e8fac0-487a-11e8-ad4e-c471feb11e42","token":"d6897a230fd7739e601649bf5fd89ea4b93317f6","expiry":"2018-04-27T17:49:48.721278Z"}
                val jelement = JsonParser().parse(it.getValue(true))
                val jobject = jelement.asJsonObject

                // save field for class-scope access
                Constants.token = jobject.get("token").asString
                Constants.id = jobject.get("id").asString
            }
            else{
                Toast.makeText(this@LoginActivity, it.getValue(false), Toast.LENGTH_SHORT).show()
            }
        }

        test = Constants.id // here test variable surely set if result was successful, otherwise it holds the null value
        test?.let{
            resultDelivered(it)
        }

    }[30, TimeUnit.SECONDS]

}

fun resultDelivered(id: String){
    // here we know that the async job has successfully finished
}

以上是关于Android(Kotlin) - 如何等待异步任务完成?的主要内容,如果未能解决你的问题,请参考以下文章

Android Kotlin协程coroutine

如何使用异步等待处理多个异常

如何等待来自 for 循环的多个异步调用?

Android - Kotlin:异步返回值

如何在Android java插件端等待异步操作(任何I / O)?

Android,Kotlin妙用suspendCancellableCoroutine,同步执行异步回调代码