Android における
ライフサイクル

@nobuoka / id:nobuoka
(リクルートマーケティングパートナーズ)
potatotips #45

@nobuoka

サーバーサイド (Java, Kotlin) / Web (TypeScript)
Android (Java, Kotlin)
  • 仕事はキッズリーのサービス開発
    • サーバーサイドに Kotlin を導入した
    • ソフトウェアエンジニア募集中です!!!
  • 最近は CircleCI 2.0 の Workflow を弄ったり
  • 個人でも仕事を請けてます

Android の辛みである
ライフサイクルに関する機能の話

  • Android Architecture Components (AAC)
    • Lifecycle-Aware Components → 便利
    • ViewModel → 使いどころを考える必要
  • Dagger の Releasable references → 便利そう

Lifecycle-Aware Components (AAC)

ライフサイクルを認識するクラスを定義できる

// ライフサイクルに応じた処理を行うクラス
class FooPresenter : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onStart() { /* 開始処理 */ }
}

// Activity の onCreate メソッド内などで登録
lifecycle.addObserver(FooPresenter())

昔似たようなライブラリを作ってた : github:nobuoka/CallbacksAppComponents

何が便利か : Activity からの分離

ライフサイクル以外のコールバックも扱える仕組みを用意すると便利 (onActivityResult とか)

ProcessLifecycleOwner

  • 複数 Activity の状態遷移を繋げたライフサイクル
  • フォアグラウンドに表示されてから消えるまでとか
  • その状態にとどまる場合にイベントが発火されるぽい
    • アプリ内の画面遷移や画面回転などでは発火しない
  • ON_DESTROY はない
  • ON_PAUSEON_STOP のイベントには遅れがある

ViewModel (AAC)

“store and manage UI-related data in a lifecycle conscious way”

  • Configuration changes を超えて生存できる
  • onSaveInstanceState() メソッドはいらん子や!
  • やったね!!!! ✧◝(⁰▿⁰)◜✧
  • となるのかというと……?

そんなことはない 。゚(゚∩´﹏`∩゚)゚。

  • Configuration changes を超えて生存できる
  • Configuration changes 以外の再生成に対応できない
  • 内部では Retain Fragment が使われている

ViewModel とライフサイクル

Retain Fragment では onSaveInstanceState を使えるんやけど……

ViewModel の使いどころ

  • 向いてること :
    • ネットワーク通信の保持
    • どこかに保存されている情報の保持、など
      • 再生成時に読み込めば良い
  • 向かない : ViewModel にしかない情報の保持
    • ユーザーが入力中の値など
    • 向かないというか、別途保存の仕組みが必要
  • onSaveInstanceState とローカルストレージへの保存と ViewModel を組み合わせていい感じに』

銀の弾丸ではない

Dagger の Releasable References

(実験的機能)

背景 : アプリ全体で単一のデータストアを持ちたい (みたいな欲求)

  • static 変数や Dagger の Singleton を使う?
  • → 常にメモリ上に保持してしまう
  • 使ってないオブジェクトは開放したい!

Dagger の Releasable References

When a binding uses a scope annotation, that means that the component object holds a reference to the bound object until the component object itself is garbage-collected. In memory-sensitive environments such as Android, you may want to let scoped objects that are not currently being used be deleted during garbage collection when the application is under memory pressure.
  • スコープアノテーションを付けるとコンポーネントがインスタンスを保持し続ける
  • メモリ空き容量が減ったらその時使ってないオブジェクトは GC したいよね?

参照を解放する機能を持ったコンポーネントを作れる!

  • 基本的には強参照で持っているが、メソッドを呼び出すことで弱参照に変換できる
  • メモリが戻ったら強参照に戻すメソッドを呼ぶ
  • スコープアノテーションに @CanReleaseReferences アノテーションを付けて制御
  • まだ実験機能ぽい

Releasable References 使用例

アプリケーションのコールバックを登録して空きメモリ容量低下時に参照を解放する。

class App : Application() {
  override fun onCreate() {
    super.onCreate()
    // ReleasableReferenceManager を取得して、
    val m = component.myReleasableReferenceManager()
    // アプリケーションのコールバックを登録。
    registerComponentCallbacks(MemoryLowCallback(m))
    registerActivityLifecycleCallbacks(MemoryHighCallback(m))
  }
}

/** メモリを使っていい状況になったら呼ばれるクラス。 */
private class MemoryHighCallback(
    private val m: ReleasableReferenceManager
) : ActivityLifecycleCallbacks {
  override fun onActivityStarted(activity: Activity) {
    m.restoreStrongReferences()
  }
}

/** メモリの空き容量の低下を扱うクラス。 */
private class MemoryLowCallback(
    private val m: ReleasableReferenceManager
) : ComponentCallbacks2 {
  override fun onTrimMemory(level: Int) {
    val doRelease = when (level) {
      TRIM_MEMORY_RUNNING_MODERATE, TRIM_MEMORY_RUNNING_LOW -> false
      TRIM_MEMORY_RUNNING_CRITICAL -> true
      TRIM_MEMORY_BACKGROUND -> false
      TRIM_MEMORY_MODERATE, TRIM_MEMORY_COMPLETE -> true
      TRIM_MEMORY_UI_HIDDEN -> false
      else -> false
    }
    if (doRelease) m.releaseStrongReferences()
  }
}

@Singleton
@Component
interface ApplicationComponent {
    fun myReleasableComponent(): MyReleasableComponent

    @ForReleasableReferences(MyReleasable::class)
    fun myReleasableReferenceManager(): ReleasableReferenceManager
}

/** 参照を解放する機能を持つコンポーネント。 */
@MyReleasable
@Subcomponent
interface MyReleasableComponent {
  /* ... */
}

おわり

  • ライフサイクルの話
  • Android Architecture Components (AAC)
    • Lifecycle-Aware Components → 便利
      • ProcessLifecycleOwner もあるぞ!
    • ViewModel → 使いどころを考える必要
  • Dagger の Releasable references → 便利そう