🌐
非同期処理が終わるまで待機させる[Kotlin]
やりたいこと
coroutine とかに対応してないコードで、非同期処理の完了を callback とか使わずにシンプルに待ちたい。
課題
こういうコードだと、result の取得タイミングを制御しづらい。
# 処理完了時に result or password が呼ばれる。
# その間、処理は中断されず次の行へ進む
Amplify.Auth.signIn(
username,
password,
{ result ->
Log.i(
"AuthQuickstart",
if (result.isSignInComplete) "Sign in succeeded" else "Sign in not complete"
)
},
{ error -> Log.e("AuthQuickstart", error.toString()) }
)
AWS Amplify: https://docs.amplify.aws/lib/auth/getting-started/q/platform/android#configure-auth-category
解決策
suspendCoroutine を使う
LoginRepository.kt
import com.amplifyframework.core.Amplify
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
sealed class Result<out R> {
data class Success<out T>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
}
class LoginRepository {
suspend fun makeLoginRequest(username: String, password: String): Result<String> {
return suspendCoroutine { continuation ->
Amplify.Auth.signIn(
username,
password,
{ res ->
val result =
Result.Success(if (res.isSignInComplete) "Sign in succeeded" else "Sign in not complete")
continuation.resume(result)
},
{ error ->
val result = Result.Error(Exception(error.toString()))
continuation.resume(result)
}
)
}
}
}
continuation.resume
が呼ばれるまで suspendCoroutine
が待ってくれて、 continuation.resume(result)
の result
を return してくれる。
呼び出し側
ログイン処理の完了を待ってから startMainActivity()
が呼ばれる。
MainActivity.kt
private fun login(username: String, password: String) = MainScope().launch(Dispatchers.Main) {
when (val result = loginRepository.makeLoginRequest(username, password)) {
is Result.Success<String> -> Log.i("LoginActivity", result.data)
else -> Log.e("LoginActivity", result.toString())
}
startMainActivity()
}
suspendCoroutine とは
このあたりが良さそうな、というか、これを読めばこの記事いらなそう…
あとがき
Good プラクティスではない気はしている。
今回例として挙げた Amplify
では、より良い形がここで議論されていそう。
Discussion