搜尋全站文章

沒有找到相關文章

試試其他關鍵字或檢查拼寫

找到 0 篇文章 • 包含部落格、筆記、旅遊文章

Medium GitHub LinkedIn

【Kotlin】非同步處理與 Coroutines

作者頭像
Sam

最近發佈

5分鐘閱讀

【Kotlin】非同步處理與 Coroutines

為什麼需要 Coroutines

想像現在有一段程式碼

fun main() { println("Feed Cat") println("Clean House") println("Feed Cat") println("Feed Cat") } main()

非同步處理

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(private val responseParser: LoginResponseParser) { private const val loginUrl = "https://example.com/login" // Function that makes the network request, blocking the current thread fun makeLoginRequest( jsonBody: String ): Result<LoginResponse> { val url = URL(loginUrl) (url.openConnection() as? HttpURLConnection)?.run { requestMethod = "POST" setRequestProperty("Content-Type", "application/json; utf-8") setRequestProperty("Accept", "application/json") doOutput = true outputStream.write(jsonBody.toByteArray()) return Result.Success(responseParser.parse(inputStream)) } return Result.Error(Exception("Cannot open HttpURLConnection")) } }

這是一個 HTTP Request 的方法,如果在 main thread 直接執行會造成阻塞,並讓畫面上的 UI 互動,直到收到回應。

因此 Kotlin 可以使用 coroutines 來處理這個問題,可以宣告一個輕量化的子執行緒(IO),並在背景執行 HTTP Request 的方法,這樣就不會阻塞 UI 畫面了。

如何使用 Coroutines

  • suspend 函數:用來宣告一個可以被中斷的函數。
  • launch, async 函數:用來啟動一個新的子執行緒。
  • withContext 函數:用來切換到指定的執行緒。

首先在我們的 LoginRepository

class LoginRepository(private val responseParser: LoginResponseParser) { suspend fun makeLoginRequest( ): Result<LoginResponse> { return withContext(Dispatchers.IO) { val url = URL(loginUrl) (url.openConnection() as? HttpURLConnection)?.run { requestMethod = "POST" setRequestProperty("Content-Type", "application/json; utf-8") setRequestProperty("Accept", "application/json") doOutput = true outputStream.write(jsonBody.toByteArray()) return Result.Success(responseParser.parse(inputStream)) } return Result.Error(Exception("Cannot open HttpURLConnection")) } } }

LoginViewModel

class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel() { fun login(username: String, password: String) { viewModelScope.launch { val result = loginRepository.makeLoginRequest(username, password) } } }

login_layount.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".LoginActivity"> <EditText android:id="@+id/username" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="text" android:hint="Username" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" /> <EditText android:id="@+id/password" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="text" android:hint="Password" app:layout_constraintTop_toBottomOf="@+id/username" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" /> <Button android:id="@+id/login" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Login" app:layout_constraintTop_toBottomOf="@+id/password" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" /> </LinearLayout>

login_activity.kt

class LoginActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.login_layout) val } } ## 參考資料 1. [Additional resources for Kotlin coroutines and flow](https://developer.android.com/kotlin/coroutines/additional-resources)

探索更多精彩內容

繼續閱讀,了解更多技術與個人經歷的精彩文章。