Kotlin入門シリーズ:Coroutine協程

13136 ワード

1協程の概念と基本的な使用
1.1協業とは
コモンCoroutineは、実際にはKotlinで提供されているスレッドAPIのセットであり、スレッドにあまり関心を持たなくても簡単に同時操作を書くことができます(すなわち、コモンはスレッドフレームワークであり、Kotlinでスレッドを便利に使用することができます.同じコードブロックで何度もスレッドを切り替えることができるのが便利です).
1.2コンシステントの基本使用
コパスを使用する場合、一般的には、関数launch()を使用してコパスを作成し、launch()関数で切り替えるスレッドを指定します.一般的には、バックグラウンドスレッドとプライマリスレッドを表すDispatchers.IODispatchers.Mainがあります.launch()関数ブロックに包まれたコードは、コヒーレントである.
//            
launch(Dispatchers.IO) {
	saveToDatabase(data)
}
//            
launch(Dispatchers.Main) {
	updateViews(data)
}
// Thread
thread {
	...
}

実際の開発では,ネットワーク要求が時間のかかる操作を実行し,結果を得てUIを更新することが多く,スレッド切替にはwithContext()を用いてスレッドの切替を行うこともでき,実行が完了すると自動的にスレッドを切り替えることができる,これがコラボレーションである.
//            ,       !!!
launch(Dispatchers.IO) {
	val user = api.getUser()
	launch(Dispatchers.Main) {
		nameTv.text = user.name
	}
}

//      
// Coroutine                   
launch(Dispatchers.Main) {
	//   withContext()                 
	val user = withContext(Dispatchers.IO) {
		api.getUser() //     :    
	}

	withContext(Dispatchers.IO) { ... }
	withContext(Dispathers.IO) { ... }	
	...
	
	nameTv.text = user.name //   UI:   
}

//     withContext()                      
launch(Dispatchers.Main) {
	val user = suspendingGetUser()
	nameTv.text = user.name
}

suspend fun suspendingGetUser() {
	withContext(Dispatchers.IO) {
		api.getUser()
	}
}

launch(Dispatchers.Main) {
	val avatar = async { api.getAvatar(user) } //           
	val logo = async { api.getCompanyLogo(user) } //       logo
	val merged = suspendingMerge(avatar, logo) //       
	show(merged) //   
}

2 suspendサスペンション
2.1契約の保留とは
掛けてあるのは何ですか.掛けてあるのは協程です.上で説明した協程はlaunch()関数に包まれたコードであり、コードが保留関数に実行されると、協程は現在のスレッドから保留されます.コプロセッサが操作を実行すると、スレッドは自動的に現在のスレッドに戻されます(簡単に理解すると、実際にはスレッドが切断され、具体的には後で自動的に切り替えられるスレッドが切り替えられます).
launch(Dispatchers.Main) {
	//  launch()         ,          
	//           suspendingGetImage()   ,            
	//                          , suspendingGetImage()               ,
	//            ,            
	//        ?suspendingGetImage()          Dispatchers.IO     
	//        ?                         , Dispatchers.IO   Dispatchers.Main
	val image = suspendingGetImage(imageId)
	avatarIv.setImageBitmap(image)
}

//       suspend       
suspend fun suspendingGetImage(imageId: String) {
	witchContext(Dispatchers.IO) {
		api.getImage(imageId)
	}
}

2.2 suspendの役割
2.2.1 suspendサスペンション関数がコモンまたは別のサスペンション関数で呼び出される理由
上記のコードでは、launch()suspendingGetImage()を使用しているときに、suspendキーワードがIDEでエラーを報告していないと、保留関数がコモンで呼び出されるか、別の保留関数で呼び出されるかを示すメッセージが表示されます.
上の説明から分かるように、保留するにはresumeを復元する必要があり、関数切替スレッドを保留した後にスレッドを切替戻す必要がありますが、resumeという機能を復元するにはコヒーレンスなので、1つの保留関数がコヒーレンスで呼び出されなければ、関数切替スレッドを保留した後にスレッドを再切替することはできません.
2.2.2 suspendキーワードの役割は何ですか
suspend fun suspendingPrint() {
	println("Thread: ${Thread.currentThread().name}")
}

suspend fun suspendingGetImage(imageId: String) {
	withContext(Dispatchers.IO) {
		api.getImage(imageId)
	}
}

launch(Dispatchers.Main) {
	//      Main   ,                 ,           
	//     ,          ,      suspendingGetImage()        ,     withContext(Dispatchers.IO)            
	//   suspend                      
	suspendingPrint() 
}

上記の分析によると、suspendキーワードはスレッドを閉じる機能やスレッドを切り替える役割を果たしていないが、それはいったい何に使われているのだろうか.suspendキーワードは、関数の作成者が関数の呼び出し者に注意するために使用される.suspendキーワード宣言のサスペンション関数は時間のかかる操作であり、関数の作成者はサスペンション方式で操作をバックグラウンドで実行しているので、関数の呼び出し者にこの関数を呼び出してください.
Javaを書くときに中のコードがメインスレッドで関数操作を呼び出していることに気づかないと、スレッドカートンやANRになります.Kotlinでsuspendキーワードで保留関数を宣言して呼び出し者にこの関数が時間のかかるバックグラウンドで実行されるタスクであることを警告すれば、このようなメインスレッドで時間のかかる操作を呼び出す問題を回避することができます.
3非ブロックサスペンション
3.1非ブロックサスペンションとは
非ブロック式ですが、実はスレッドが詰まっていません.Kotlinの保留関数を使ってスレッドを切るにしても、JavaのThreadでスレッドを切るにしても、実は非ブロック式です.
したがって、コヒーレントな非ブロック式サスペンションは、実際にはブロック方式で非ブロックのコードを書いただけで、本質的に時間のかかる操作なのかスレッドを切らなければならないのか、更新インタフェースなのか、受賞者スレッドなのか(いずれのコードもブロックされているが、時間のかかる操作のコードは人間の感知の中で明らかであるだけだ).
3.2スレッドとスレッドの関係
Kotlinでは、JavaのExecutorsとAndroidのHandler APIに似たスレッドによって実現されるより上位レベルのツールAPIフレームワークです.コヒーレンスの本質はスレッドです.
4まとめ
  • コパスは、スレッド
  • である.
  • が掛けられているのは、自動的に切り取ることができるスレッド
  • である.
  • 非ブロック式は、ブロックされているように見えるコードで非ブロックの動作
  • を書くことができるコヒーレンスである.