Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AndroidでKotlin Coroutineを使うときの注意点 | CA BASE NEXT

AndroidでKotlin Coroutineを使うときの注意点 | CA BASE NEXT

Androidアプリ開発において、非同期処理は欠かせないテクニックです。画面の描画を妨げることなく、ネットワークリソースにアクセスしたり、データベースにリクエストする必要があります。また、計算量の多い処理は別スレッドで実行することで、パフォーマンスを改善することができるでしょう。
Kotlin Coroutinesはそれらを強力に支援してくれます。最近ではRetrofitやRoom、DataStoreを始めとした周辺ライブラリもCoroutinesをサポートし、ますます使いやすさが増しています。
一方で、Coroutinesを利用する上で、保守性やテスト容易性の面で、いくつか注意する点があります。また、Lifecycleやエラーハンドリングなどでは、間違えやすいポイントも存在します。
このLTでは、すでにKotlin Coroutinesを使ってAndroidアプリを開発している方に向け、Coroutinesを使う際の注意点を解説します。ぜひ今後の参考にしてもらえると幸いです。

https://ca-base-next.cyberagent.co.jp/sessions/android-kotlin-coroutines

A45681c58220b58ca83a926b1be52e65?s=128

Mori Atsushi

May 27, 2021
Tweet

Transcript

  1. None
  2. Mori Atsushi 2019年度 新卒⼊社 株式会社CyberZ OPENREC.tv CyberZ CTO室 メンバー 次世代マネジメント室

    メンバー 未踏スーパークリエータ @at_sushi_at @Mori-Atsushi
  3. https://note.com/cyberz_cto/n/n f d c

  4. https://zenn.dev/at_sushi_at/books/edf adfc

  5. • Kotlinの公式ライブラリ • ⾮同期処理を強⼒に⽀援、まるで同期処理のように書ける Kotlin Coroutines Kotlin Coroutines Features/Promises/Rx

  6. • Googleも推奨するソリューション • AndroidのLifecycleに沿ったキャンセルを実現可能 • 周辺ライブラリもCoroutinesをサポート Retrofit, grpc-kotlin, Room, DataStore,

    Paging , Store , Jetpack Compose Android 🤝 Kotlin Coroutines • Lifecycle, Dispatchers, CoroutineContext, エラーハンドリング, キャンセル処理, バッファ 注意する点は多い
  7. 🚀 今回のゴール 既にKotlin Coroutinesを使って Androidアプリを開発している⽅に向け、 キャンセルについてより詳しく知ってもらう。 • より安全に • より効率的に

    • より保守しやすいよう
  8. ໨࣍ Contents ໨࣍ Contents ໨࣍ Contents ໨࣍ Contents ໨࣍ Contents

    . Kotlin Coroutinesのキャンセルを扱う 2. 正しくキャンセルする 3. 正しくキャンセルさせない
  9. . Kotlin Coroutinesのキャンセルを扱う

  10. • モバイルデバイスという限られたリソースで、 正しく処理を中断することは重要 • 例えば フォアグラウンドのときのみUIを更新する 現在の画⾯を閉じたらリクエスト中のAPIを終了する キャンセル https://developer.android.com/topic/libraries/architecture/viewmodel

  11. • CoroutinesScopeやJobは キャンセル可能 • delay等のsuspend functionが CancellationExceptionを throwしている Coroutinesのキャンセルの仕組み CancellationExceptionをthrow

    キャンセル時のハンドリング キャンセル時もそうでないときも 実⾏される
  12. • LifecycleOwner.lifecycleScope Lifecycleが破棄されたとき(onDestory)に⾃動的にキャンセルされる • ViewModel.viewModelScope ViewModelの消去時 (onCleared) に⾃動的にキャンセルされる AndroidとCoroutinesのキャンセル

  13. 2. 正しくキャンセルする

  14. 問題:以下のコードはどのように実⾏されるか? 1,000,000までインクリメント 500,000のタイミングでキャンセル

  15. 正解:1,000,000までインクリメントされる 1,000,000までインクリメント 500,000のタイミングでキャンセル 実⾏結果

  16. なぜ? • Coroutinesは常にキャンセルされたかどうかを 知っているわけではない • delay等の⼀部のsuspend functionのみ キャンセルされたかどうか確認している • キャンセルされているか確認するタイミングが

    なければ、最後まで実⾏される
  17. • ensureActiveでキャンセルされてないか確認する 注意点①:キャンセルに対して協⼒的である必要がある 500,000のタイミングでキャンセル 1,000,000までインクリメント 実⾏結果 キャンセルされていれば CancellationExceptionをthrow

  18. どのようなコードで考慮すべきか? • 通常の処理で問題になることは少ない あちこちにキャンセルチェックがあると、 本質と異なる情報が混じり可読性が落ちる • 例えば: バックグランドスレッドで重たいアルゴリズムを動作させている場合 ディスクから複数のファイルを読み込む場合

  19. 注意点②:suspendCancellableCoroutineを使う • callback処理をsuspend function に変更するsuspendCoroutineは キャンセルに対応していない • 可能な限り suspendCancellableCoroutine を使う

    キャンセル時の処理
  20. 注意点③: CancellationExceptionをcatchしない • キャンセル時にthrowされる CancellationExceptionも catchしてしまうと キャンセルされない キャンセルされてもリトライしてしまう キャンセル時に CancellationExceptionをthrowする

    エラーになった際にretryする関数
  21. 解決策 • 特定のエラーだけ try-catchする • CancellationExceptionを 再throwする エラーになった際にretryする関数 キャンセル時に CancellationExceptionをthrowする

    キャンセルを呼び出し元に 伝播させる
  22. 3. 正しくキャンセルさせない

  23. • 画⾯を閉じた際等にキャンセルさせたくない 処理も存在する • 例えば 購⼊完了後のレシート処理 ログ送信処理 キャンセルさせたくない処理 ViewModel破棄後も続⾏させたい

  24. 良くない⽅法:GlobalScopeを使う • アプリケーション期間のCoroutineScope (@DelicateCoroutinesApi) • contextが不明瞭 Dispatcherは? JobかSupervisorJobか? エラーハンドリングは? •

    テストでも キャンセルができない ViewModel破棄後も続⾏される GlobalScopeでlaunch
  25. 注意が必要:NonCancellableを利⽤する • キャンセルできないJob • 記述はシンプルでわかりやすい • 個別のキャンセルも できなくなり、 制御が不可能 •

    テストでも キャンセルができない • クリーンアップ等では便利 ViewModel破棄後も続⾏される withContextで指定
  26. 個別のキャンセルも出来ない • withContext(NonCancellable) はいかなる⽅法でも キャンセルできない • 将来的に予期せぬ不具合を 引き起こす可能性がある jobをcancelしてもapi.purchaseは続⾏される

  27. おすすめ:アプリケーション範囲のCoroutineScopeをDIする • CoroutineScopeを⾃作 • テストで制御可能 • 共通のcontextが利⽤可能 • 個別の制御も可能 ViewModel破棄後も続⾏される

    appScopeでlaunch エラーハンドラー JobやDispatcher appScopeを定義
  28. まとめ • キャンセルを意識することでリソースを効率的に扱うことが出来る • 正しくキャンセルさせる キャンセルに対して協⼒的である必要がある suspendCancellableCoroutineを使う CancellationExceptionをcatchしない • 正しくキャンセルさせない

    アプリケーション範囲のCoroutineScopeをDIする
  29. 参考⽂献 • Mori Atsushi, 詳解 Kotlin Coroutines [ ], https://zenn.dev/at_sushi_at/books/edf

    adfc • Kotlin coroutines on Android | Android Developers, https://developer.android.com/kotlin/ coroutines • Best practices for coroutines in Android | Android Developers, https://developer.android.com/ kotlin/coroutines/coroutines-best-practices • Cancellation in coroutines. Cancellation and Exceptions in | by Florina Muntenescu | Android Developers | Medium, https://medium.com/androiddevelopers/cancellation-in-coroutines- aa b • Coroutines & Patterns for work that shouldn’t be cancelled | by Manuel Vivo | Android Developers | Medium, https://medium.com/androiddevelopers/coroutines-patterns-for-work-that-shouldnt-be- cancelled-e c f ad
  30. None