Android:Coroutine(コルーチン)について
Coroutine(コルーチン)とは?
- 非同期処理ライブラリ。コードが簡潔でメモリのコストが小さいメリットがある
Coroutine(コルーチン)ライブラリの導入方法
- build.gradle(:app)に一行追加
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
Coroutine(コルーチン)を扱うに当たっての各キーワード
- CoroutineScope
- Coroutineを扱う上で全ての土台となるもの
- GlobalScope
- CoroutineScopeを継承したスコープで、非同期処理を実装出来る
- GlobalScope.lanch
- 実行中のスレッドはそのままで新しいスレッドを作成する。新しく作成したスレッドはJobインスタンスとして取得でき、Jobインスタンスのメソッドを使うとGrobalScope内で実装した処理が終わるまで次の処理を行わないやGrobalScope内で実装した処理を行わないなど処理に対して制限をかけることもできる
fun launchTest() {
println("処理1")
// GlobalScope.launch はJobインスタンスを返す
// GlobalScope.launchのスコープ内で起動機処理を定義
GlobalScope.launch {
println("処理2")
}
println("処理3")
}
- Job
- GrobalScope.launch{}で新たにスレッドを作成した際に得られるインスタンス。Job型のインスタンスにはいくつかメソッドがある。Job.join()はJob(GrobalScope.launch{})内の処理が終わるまで次の処理に進まないようにするためのメソッド。Job.cancel()はJob(GrobalScope.launch{})内の処理をcancel()がよばれた以降行わないようにするためのメソッド
- suspend fun
- メソッド定義の際につける事ができ、'suspend fun'を付けるとめメソッド内の処理が終わるまで他の処理は一時停止する。使用上の注意点としては'suspend fun'で定義したメソッドはCoroutine(コルーチン)内でしか使えない。
fun launchTest() {
println("処理1")
// GlobalScope.launch はJobインスタンスを返す
// GlobalScope.launchのスコープ内で起動機処理を定義
GlobalScope.launch {
suspendTest()
println("処理2")
}
println("処理3")
}
private suspend fun suspendTest() {
// delay(3000)後に実行される
delay(3000)
println("処理4")
}
- runBlocking
- runBlockingで囲った処理が終わるまで囲った処理以外を一時停止する事ができる。注意点はCoroutine(コルーチン)外でしか使う事ができない。(元のスレッド(例:メインスレッド)とCoroutine(コルーチン)で作成したスレッドの橋渡し的な役目で使用すると良い)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
println("runBlocking、始めるで〜")
// runBlockingを使用している為、runBlocking内の処理が終わってからしたの行の処理を行う
runBlockingTest()
println("runBlocking、終わったで〜")
}
private fun runBlockingTest() = runBlocking {
println("処理1")
GlobalScope.launch {
println("処理2") // delay(3000)の間に実行される
}
// Thread.sleep(1000) // 実行中の全スレッドを1秒止める
delay(3000) // coroutine(ここではrunBlocking)内の処理のみ3秒止める
println("処理3")
}
- withContext
- Coroutine(コルーチン)内でのみ使用できる、withContext{}内の処理が終わるまでCoroutine(コルーチン)内の処理を一時停止できる機能。Coroutine(コルーチン)内の一部の処理で一時停止したい場合におすすめ
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
println("runBlocking、始めるで〜")
// runBlockingを使用している為、runBlocking内の処理が終わってからしたの行の処理を行う
runBlockingTest()
println("runBlocking、終わったで〜")
}
private fun runBlockingTest() = runBlocking {
println("処理1")
withContext(Dispatchers.Default) {
delay(3000)
println("処理2") // delay(3000)後に実行される
}
println("処理3")
}
Android:Activity破棄について
Activity破棄対応
Activity破棄が起きるタイミング
- 画面回転時
- バックグラウンドからフォアグラウンドへ戻る間にメモリの割り当てがなくなった時
Activity破棄が起きるとどういった事が起きるか
- 画面の再生成
- 画面生成時のデータの初期化 -> データの初期化が起きると画面で表示していたデータが異なるという不具合が起きる
どう対応するか?
1.Activity破棄時に'onSaveInstanceState'で必要なデータを保存する
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// Activity破棄時に値を保存する
outState.putInt(CURRENT_NUMBER_OF_TIMES_KEY, numberOfTimes)
}
2.復帰時は'onCreate'から走るので、'Bundle'から保存した値を取得し必要な箇所にデータをセットして復元する
3.(必要あれば)'onSaveInstanceState'で保存した値はライフサイクルのメソッドの'Bundle'引数に入っているので、'Bundle'内のデータの有無で処理を分けるとActivity破棄・復帰後の対応がより詳細に対応できる
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val textView = view.findViewById<TextView>(R.id.text)
val button = view.findViewById<Button>(R.id.button)
// Activity破棄時に保存した値を取得
numberOfTimes = savedInstanceState?.getInt(CURRENT_NUMBER_OF_TIMES_KEY) ?: 0
textView.text = numberOfTimes.toString()
button.setOnClickListener {
textView.text = (++numberOfTimes).toString()
}
if (savedInstanceState != null) {
parentFragmentManager.beginTransaction().replace(R.id.mainActivity,
RelayScreenFragment()).addToBackStack("").commit()
}
}
Activity破棄復帰時の特徴
- Activity破棄復帰時はActivityから破棄前に表示していた画面までのライフサイクルが新たに'Add'や'Replace'を行わなくても自動で走る特徴がある
-> つまりActivity破棄を何も顧慮しないで実装を行うと、Activity破棄前の画面のライフサイクルが自動で走る + 'Add'や'Replace'で新規画面作成を行う為、同じ画面が多重で生成・表示される場合があるので考慮してActivity破棄対応を行う必要がある。