Web ページの取得や API との対話はどちらもネットワーク リクエストを行うことを伴います。 同様に、データベースからの読み取りやディスクからのイメージのロードは、ファイルの読み取りを伴います。 これらの種類は、私が長時間実行タスクと呼んでいるもので、アプリが停止して待機するにはあまりにも時間がかかりすぎるタスクです!
class ViewModel: ViewModel() { fun fetchDocs() { get("developer.android.com") { result -> show(result) } } }
get がメイン スレッドから呼び出されたとしても、ネットワーク リクエストを実行するために別のスレッドを使用します。 そして、ネットワークから結果が得られると、メインスレッドでコールバックが呼び出される。 これは、長時間実行するタスクを処理する優れた方法で、Retrofit などのライブラリは、メイン スレッドをブロックせずにネットワーク リクエストを行うのに役立ちます。 コルーチンが長時間実行するタスクのコードをどのように単純化するかを調べるために、コルーチンを使用するように上記のコールバックの例を書き換えてみましょう。
// Dispatchers.Main suspend fun fetchDocs() { // Dispatchers.Main val result = get("developer.android.com") // Dispatchers.Main show(result) }// look at this in the next section suspend fun get(url: String) = withContext(Dispatchers.IO){/*...*/}
このコードはメインスレッドをブロックしないのでしょうか。 ネットワーク要求を待たず、ブロックすることなく、どのように get から結果を返すのでしょうか。
Suspend と resume は、コールバックを置き換えるために一緒に動作します。 関数 get はメインスレッドからネットワークリクエストを実行する責任を持ったままである。 そしてネットワーク要求が完了すると、メインスレッドに通知するためにコールバックを呼び出すのではなく、単に中断したコルーチンを再開することができる。
Animation showing how Kotlin implemented suspend and resume to replace callbacks.
Looking how fetchDocs executes, you can see how suspend works.Limited は、どのように実行されるかを見ることで、サスペンドがどのように機能するかを見ることができます。 コルーチンが中断されるたびに、現在のスタックフレーム(Kotlin がどの関数が実行されているか、その変数を追跡するために使用する場所)がコピーされ、後のために保存されます。 再開すると、スタックフレームは保存された場所からコピーバックされ、再び実行を開始します。 アニメーションの途中、つまりメインスレッドのコルーチンがすべてサスペンドされると、メインスレッドは自由に画面の更新やユーザーイベントの処理ができるようになります。 サスペンドとレジュームが一緒になって、コールバックを置き換えているのです。 7509>
When the coroutines all of the main thread are suspended, the main thread is free to do other work.
When we wrote straightforward sequential code that looks exactly like a blocking network request, coroutines will run our code exactly how we want and avoid blocking the main thread.When the coroutines are all of the main thread is suspended… (参照: 『コルーチン』)