Kotlin класс возвращает false до того, как закончил - PullRequest
0 голосов
/ 13 января 2020

В моей основной деятельности у меня есть функция, которая запускается после нажатия кнопки входа в систему. Я вызываю класс, который пытается войти через API, который запускается через секунду или две. Однако, когда я вызываю класс входа в систему, он кажется многопоточным и не ждет завершения входа в систему и возвращает false, что является значением по умолчанию. Пример кода выглядит следующим образом:

class MainActivity : BaseActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

        fun loginBtnClicked(view: View) {

        progressBar.visibility = View.VISIBLE

        // get domain info
        val domain: TextView = findViewById<TextView>(R.id.loginDomain)
        val domainUrl = domain.text.toString()
        val url = "$domainUrl/api/"

        // get username info
        val username = loginUsername
        // get password info
        val password = loginPassword

        if (ApiGet(
                url = url,
                username = username.text.toString(),
                password = password.text.toString()
            ).login()) {
            println("It worked")
            val dashboard = Intent(this, DashboardActivity::class.java)
            Consts.DOMAIN = url
            Consts.USERNAME = username.text.toString()
            Consts.PASSWORD = password.text.toString()
            startActivity(dashboard)
        } else {
            println("It didn't work")
            progressBar.visibility = View.INVISIBLE
            runOnUiThread {
                Log.i(ContentValues.TAG, "runOnUiThread")
                Toast.makeText(
                    applicationContext,
                    "Please check the domain, username and password then try again.",
                    Toast.LENGTH_SHORT
                ).show()
            }
        }
    }
}


class ApiGet(val url: String, val username: String = Consts.USERNAME, val password: String = Consts.PASSWORD) {

    fun login(): Boolean {

        var loginAttempt: Boolean = false
        var apiData: ApiLogin
        val creds = Credentials.basic(username, password)
        val request = Request.Builder().url(url).header("Authorization", creds).build()
        val client = OkHttpClient()

        client.newCall(request).enqueue(
            object : Callback {
                override fun onResponse(call: Call, response: Response) {
                    val body: String? = response.body()?.string()
                    val gson: Gson = GsonBuilder().create()
                    apiData = gson.fromJson(body, ApiLogin::class.java)

                    if (apiData.detail == "Invalid username/password.") {
                        loginAttempt = false
                        println(loginAttempt)
                    } else {
                        loginAttempt = true
                        println(loginAttempt)
                    }
                }


                override fun onFailure(call: Call, e: IOException) {
                    Toast.makeText(
                        MainActivity().getApplicationContext(),
                        "Please check your connection and try again.",
                        Toast.LENGTH_SHORT
                    ).show()
                    loginAttempt = false
                }
            })

        return loginAttempt
    }
    class ApiLogin(val detail: String)
}

1 Ответ

2 голосов
/ 13 января 2020

Это потому, что ваш newCall метод запускается в асинхронном режиме c с основным потоком, что означает, что остальная часть вашего кода продолжает выполняться после его вызова, пока он ожидает в другом потоке. Чтобы исправить это, а не возвращать свой результат, вы можете обработать его в обратном вызове следующим образом:

class ApiGet(val url: String, val username: String = Consts.USERNAME, val password: String = Consts.PASSWORD) {

    fun login(completion: (Boolean)->Unit) {

        var loginAttempt: Boolean = false
        var apiData: ApiLogin
        val creds = Credentials.basic(username, password)
        val request = Request.Builder().url(url).header("Authorization", creds).build()
        val client = OkHttpClient()

        client.newCall(request).enqueue(
            object : Callback {
                override fun onResponse(call: Call, response: Response) {
                    val body: String? = response.body()?.string()
                    val gson: Gson = GsonBuilder().create()
                    apiData = gson.fromJson(body, ApiLogin::class.java)

                    if (apiData.detail == "Invalid username/password.") {
                        println(loginAttempt)
                        completion(False)
                    } else {
                        print(loginAttempt)
                        completion(True)
                    }
                }


                override fun onFailure(call: Call, e: IOException) {
                    Toast.makeText(
                        MainActivity().getApplicationContext(),
                        "Please check your connection and try again.",
                        Toast.LENGTH_SHORT
                    ).show()
                    completion(False)                }
            })
    }

Вы можете вызвать функцию входа в систему следующим образом:

ApiGet(url = url,
       username = username.text.toString(),
       password = password.text.toString()).login { result ->

       if (result) {
            // success
       } else {
            // failure
       }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...