AndroidArchitectureComponent勉強会 vol 5

# Android Architecture Component 勉強会
GDG東京産主催の勉強会です。
今回は5回目で、Lifecycle, ViewModel, LiveData の復習です。
https://gdg-tokyo.connpass.com/event/123068/

資料はこちら
https://developer.android.com/topic/libraries/architecture/index.html
https://speakerdeck.com/yanzm/lifecycle-viewmodel-livedata-falsefu-xi

あんざいさんのスライドを見れば一撃ですが、ぼくは頭にスッと入ってこないので、
ここに書き記しながらやっていきます。
# Android Architecture Componentsとは
そもそもAndroid Architecture Componentsがわからないといけないですが、
以下が公式での説明です。

`Android architecture components are a collection of libraries that help you design robust, testable, and maintainable apps. Start with classes for managing your UI component lifecycle and handling data persistence.` 

# ここから勉強内容

## LifeCycles
* LifeCycle aware-components
* ライフサイクルを感知する
* ActivityやFragmentのライフサイクルの状態が変わったときのアクションを制御することができる

### LifeCycle.State
現在のライフサイクル状態を表すenum
* INITIALIZED
* DESTROYED
* CREATED
* STARTED
* RESUMED

### LifeCycle.Event
ライフサイクル状態が変わったことを表すenum
* ON_CREATE
* ON_START
* ON_STOP
* ON_RESUME
* ON_PAUSE
* ON_DESTROY
* ON_ANY ←これは？

### LifeCycleOwner
* クラスがLifeCycleを持つことを表すsingle method interface
* FragmentActivityの親クラスのComponentActivityがこれを実装してる　←　ま　じ　か
* FragmentはLifeCycleを実装している　←　ま　じ　か
→ということはbuild.gradleでimplementationすればすぐに使えるってこと（か？）

## LiveData

## ViewModel
* LiveDataと併用して使われることが多い。

メモ
# LifeCycleEventObserver
* すべてのlifecycle changeを受け取れるinterface

# distinctUntilChanged
* もとのLivedataの値が変わるまで値を返さない

# ktx extensions

```
viewModel.liveData.map {
}

viewModel.liveData.switchMap {
}

viewModel.liveData.distinctUntilChanged() {
}

viewModel.liveData.observe(this) {
}
```

# ViewModel.viewModelScope
* lifecycle-viewmodel-ktx
* ViewModelに紐付いたCoroutineScope
 * Dispatcherd.main（メインスレッド）

# ViewModel Savedstate


# 課題1.1
## 結果

```
2019-03-25 20:30:38.917 3644-3644/app.kemura.aac_studies I/System.out: onCreate : INITIALIZED
2019-03-25 20:30:38.926 3644-3644/app.kemura.aac_studies I/System.out: onStart : CREATED
2019-03-25 20:30:38.933 3644-3644/app.kemura.aac_studies I/System.out: onResume : STARTED
2019-03-25 20:32:07.960 3644-3644/app.kemura.aac_studies I/System.out: onPause : STARTED
2019-03-25 20:32:08.008 3644-3644/app.kemura.aac_studies I/System.out: onStop : CREATED
2019-03-25 20:32:17.503 3644-3644/app.kemura.aac_studies I/System.out: onStart : CREATED
2019-03-25 20:32:17.508 3644-3644/app.kemura.aac_studies I/System.out: onResume : STARTED
2019-03-25 20:32:25.372 3644-3644/app.kemura.aac_studies I/System.out: onPause : STARTED
2019-03-25 20:32:26.416 3644-3644/app.kemura.aac_studies I/System.out: onStop : CREATED
2019-03-25 20:32:27.729 3644-3644/app.kemura.aac_studies I/System.out: onDestroy : DESTROYED
```

# 課題2.1, 2.2
コード

```
package app.kemura.aac_studies

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Lifecycleに登録
        val lifecycleObserver = object: LifecycleObserver {
            @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
            fun onCreate() {
                println("onCreate : ${lifecycle.currentState.name}")
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
            fun onResume() {
                println("onResume : ${lifecycle.currentState.name}")
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_START)
            fun onStart() {
                println("onStart : ${lifecycle.currentState.name}")
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
            fun onStop() {
                println("onStop : ${lifecycle.currentState.name}")
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
            fun onPause() {
                println("onPause : ${lifecycle.currentState.name}")
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
            fun onDestroy() {
                println("onDestroy : ${lifecycle.currentState.name}")
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
            fun onAny(source: LifecycleOwner, event: Lifecycle.Event) {
                println("onAny : ${source.lifecycle.currentState.name}")
            }
        }
        lifecycle.addObserver(lifecycleObserver)
    }
}
```

結果

```
2019-03-25 20:40:28.799 5820-5820/app.kemura.aac_studies I/System.out: onCreate : CREATED
2019-03-25 20:40:28.799 5820-5820/app.kemura.aac_studies I/System.out: onAny : CREATED
2019-03-25 20:40:28.803 5820-5820/app.kemura.aac_studies I/System.out: onStart : STARTED
2019-03-25 20:40:28.803 5820-5820/app.kemura.aac_studies I/System.out: onAny : STARTED
2019-03-25 20:40:28.812 5820-5820/app.kemura.aac_studies I/System.out: onResume : RESUMED
2019-03-25 20:40:28.812 5820-5820/app.kemura.aac_studies I/System.out: onAny : RESUMED
2019-03-25 20:40:42.242 5820-5820/app.kemura.aac_studies I/System.out: onPause : STARTED
2019-03-25 20:40:42.243 5820-5820/app.kemura.aac_studies I/System.out: onAny : STARTED
2019-03-25 20:40:42.266 5820-5820/app.kemura.aac_studies I/System.out: onStop : CREATED
2019-03-25 20:40:42.267 5820-5820/app.kemura.aac_studies I/System.out: onAny : CREATED
2019-03-25 20:40:51.721 5820-5820/app.kemura.aac_studies I/System.out: onStart : STARTED
2019-03-25 20:40:51.722 5820-5820/app.kemura.aac_studies I/System.out: onAny : STARTED
2019-03-25 20:40:51.722 5820-5820/app.kemura.aac_studies I/System.out: onResume : RESUMED
2019-03-25 20:40:51.722 5820-5820/app.kemura.aac_studies I/System.out: onAny : RESUMED
2019-03-25 20:40:56.986 5820-5820/app.kemura.aac_studies I/System.out: onPause : STARTED
2019-03-25 20:40:56.986 5820-5820/app.kemura.aac_studies I/System.out: onAny : STARTED
2019-03-25 20:40:57.630 5820-5820/app.kemura.aac_studies I/System.out: onStop : CREATED
2019-03-25 20:40:57.630 5820-5820/app.kemura.aac_studies I/System.out: onAny : CREATED
2019-03-25 20:40:57.633 5820-5820/app.kemura.aac_studies I/System.out: onDestroy : DESTROYED
2019-03-25 20:40:57.634 5820-5820/app.kemura.aac_studies I/System.out: onAny : DESTROYED
```

# 課題2.3のコード

```
package app.kemura.aac_studies

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Lifecycleに登録
        val lifecycleObserver = object: LifecycleObserver {
            @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
            fun onCreate() {
                println("onCreate : ${lifecycle.currentState.name}")
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
            fun onResume() {
                println("onResume : ${lifecycle.currentState.name}")
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_START)
            fun onStart() {
                println("onStart : ${lifecycle.currentState.name}")
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
            fun onStop() {
                println("onStop : ${lifecycle.currentState.name}")
                lifecycle.removeObserver(this) // ここで解除
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
            fun onPause() {
                println("onPause : ${lifecycle.currentState.name}")
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
            fun onDestroy() {
                println("onDestroy : ${lifecycle.currentState.name}")
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
            fun onAny(source: LifecycleOwner, event: Lifecycle.Event) {
                println("onAny : ${source.lifecycle.currentState.name}")
            }
        }
        lifecycle.addObserver(lifecycleObserver)
    }
}
```

結果

```
2019-03-25 20:43:50.252 6186-6186/app.kemura.aac_studies I/System.out: onCreate : CREATED
2019-03-25 20:43:50.252 6186-6186/app.kemura.aac_studies I/System.out: onAny : CREATED
2019-03-25 20:43:50.257 6186-6186/app.kemura.aac_studies I/System.out: onStart : STARTED
2019-03-25 20:43:50.257 6186-6186/app.kemura.aac_studies I/System.out: onAny : STARTED
2019-03-25 20:43:50.265 6186-6186/app.kemura.aac_studies I/System.out: onResume : RESUMED
2019-03-25 20:43:50.265 6186-6186/app.kemura.aac_studies I/System.out: onAny : RESUMED
2019-03-25 20:43:58.621 6186-6186/app.kemura.aac_studies I/System.out: onPause : STARTED
2019-03-25 20:43:58.621 6186-6186/app.kemura.aac_studies I/System.out: onAny : STARTED
2019-03-25 20:43:59.195 6186-6186/app.kemura.aac_studies I/System.out: onStop : CREATED
2019-03-25 20:43:59.195 6186-6186/app.kemura.aac_studies I/System.out: onAny : CREATED
```

# 課題４
ソース

```
class MainApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        val lifecycleObserver = object: LifecycleObserver {
            @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
            fun onAny(source: LifecycleOwner, event: Lifecycle.Event) {
                println("onAny : ${source.lifecycle.currentState.name}")
            }
        }

        ProcessLifecycleOwner.get()
            .lifecycle
            .addObserver(lifecycleObserver)
    }
}
```

結果
以下を確認せよ
* ホームキーをタップしたとき

```
2019-03-25 21:04:14.850 7721-7721/app.kemura.aac_studies I/System.out: onAny : STARTED
2019-03-25 21:04:14.851 7721-7721/app.kemura.aac_studies I/System.out: onAny : CREATED
```

* RecentAppsから復帰したとき

```
2019-03-25 21:04:34.448 7721-7721/app.kemura.aac_studies I/System.out: onAny : STARTED
2019-03-25 21:04:34.451 7721-7721/app.kemura.aac_studies I/System.out: onAny : RESUMED
```

* 別のActivityにいったとき

```
2019-03-25 21:02:30.171 7721-7721/app.kemura.aac_studies I/System.out: onAny : CREATED
2019-03-25 21:02:30.561 7721-7721/app.kemura.aac_studies I/System.out: onAny : STARTED
2019-03-25 21:02:30.564 7721-7721/app.kemura.aac_studies I/System.out: onAny : RESUMED
```

* 別のActivityから戻ってきたとき

```
なにもなし
```

* 画面回転したとき

```
なにもなし
```

# 次、LiveDataの課題
急げ
## 課題5.1
* ボタンを押したときにどんな順番で来るか

```
    private fun setUpLiveData() {
        val liveData = MutableLiveData<String>()

        liveData.observe(this, Observer {
            println(it)
        })

        val liveDataButton = findViewById<Button>(R.id.livedata_button)
        liveDataButton.setOnClickListener {
            liveData.value = "a"
            liveData.value = "b"
        }
    }
```

結果

```
2019-03-25 21:12:49.446 8180-8180/app.kemura.aac_studies I/System.out: a
2019-03-25 21:12:49.446 8180-8180/app.kemura.aac_studies I/System.out: b
```

## 課題5.2

```
    private fun setUpLiveData() {
        val liveData = MutableLiveData<String>()

        liveData.observe(this, Observer {
            println(it)
        })

        val liveDataButton = findViewById<Button>(R.id.livedata_button)
        liveDataButton.setOnClickListener {
            liveData.postValue("a")
            liveData.value = "b"
        }
    }
```

結果

```
2019-03-25 21:14:12.400 8353-8353/app.kemura.aac_studies I/System.out: b
2019-03-25 21:14:12.414 8353-8353/app.kemura.aac_studies I/System.out: a
```

## 課題5.3

```
    private fun setUpLiveData() {
        val liveData = MutableLiveData<String>()

        liveData.observe(this, Observer {
            println(it)
        })

        val liveDataButton = findViewById<Button>(R.id.livedata_button)
        liveDataButton.setOnClickListener {
            liveData.postValue("a")
            liveData.postValue("b")
        }
    }
```

結果

```
2019-03-25 21:15:05.463 8505-8505/app.kemura.aac_studies I/System.out: b
```

## 課題6.1と6.2

```
    private fun setUpLiveData() {
        val liveData = MainLiveData()

        liveData.observe(this, Observer {
            println(it)
        })
    }

    private class MainLiveData: LiveData<String>() {
        override fun onInactive() {
            super.onInactive()
            println("onInactive ${hasActiveObservers()}")
        }

        override fun onActive() {
            super.onActive()
            println("onActive ${hasActiveObservers()}")
        }
    }
```

結果
*ホームボタンをタップしたとき
 
```
2019-03-25 21:19:54.411 8726-8726/app.kemura.aac_studies I/System.out: onInactive false
```

* RecentAppsから復帰

```
2019-03-25 21:22:09.706 8726-8726/app.kemura.aac_studies I/System.out: onActive true
```

* 別のActivityに遷移

```
2019-03-25 21:22:25.311 8726-8726/app.kemura.aac_studies I/System.out: onInactive false
```

* 別のActivityから復帰

```
2019-03-25 21:22:52.395 8726-8726/app.kemura.aac_studies I/System.out: onActive true
```

* 画面回転

```
2019-03-25 21:23:37.843 8726-8726/app.kemura.aac_studies I/System.out: onInactive false
2019-03-25 21:23:37.921 8726-8726/app.kemura.aac_studies I/System.out: onActive true
2019-03-25 21:23:44.111 8726-8726/app.kemura.aac_studies I/System.out: onInactive false
2019-03-25 21:23:44.194 8726-8726/app.kemura.aac_studies I/System.out: onActive true
```

## 課題6.3

```
    private fun setUpLiveData() {
        val liveData = MainLiveData()

        val toggleButton = findViewById<ToggleButton>(R.id.toggle)
        toggleButton.setOnCheckedChangeListener { _, isChecked ->
            if (isChecked) {
                liveData.observe(this, Observer {
                    println(it)
                })
            } else {
                liveData.removeObservers(this)
            }
        }
    }
```

結果

→ON

```
2019-03-25 21:32:55.989 9335-9335/app.kemura.aac_studies I/System.out: onActive true
```

→OFF

```
2019-03-25 21:33:15.868 9335-9335/app.kemura.aac_studies I/System.out: onInactive false
```

## 課題7.1

```
    private val countUpLiveData = CountUpLiveData()
    private val observer = Observer<Int> {
        println("observeForever : $it")
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // countup
        countUpLiveData.observe(this, Observer {
            println(it)
        })
        countUpLiveData.observeForever(observer)
    }

    private class CountUpLiveData: LiveData<Int>() {
        private var count = 0
        private val handler = Handler()
        private val runnable = Runnable {
            count++
            value = count
            next()
        }

        private fun next() {
            handler.postDelayed(runnable, 1000)
        }

        override fun onActive() {
            next()
        }

        override fun onInactive() {
            handler.removeCallbacks(runnable)
        }
    }
```

結果

```
2019-03-25 21:42:35.445 9694-9694/app.kemura.aac_studies I/System.out: 1
2019-03-25 21:42:35.445 9694-9694/app.kemura.aac_studies I/System.out: observeForever : 1
2019-03-25 21:42:36.448 9694-9694/app.kemura.aac_studies I/System.out: 2
2019-03-25 21:42:36.448 9694-9694/app.kemura.aac_studies I/System.out: observeForever : 2
2019-03-25 21:42:37.450 9694-9694/app.kemura.aac_studies I/System.out: 3
2019-03-25 21:42:37.450 9694-9694/app.kemura.aac_studies I/System.out: observeForever : 3
2019-03-25 21:42:38.451 9694-9694/app.kemura.aac_studies I/System.out: 4
2019-03-25 21:42:38.451 9694-9694/app.kemura.aac_studies I/System.out: observeForever : 4
2019-03-25 21:42:39.456 9694-9694/app.kemura.aac_studies I/System.out: 5
2019-03-25 21:42:39.456 9694-9694/app.kemura.aac_studies I/System.out: observeForever : 5
2019-03-25 21:42:40.458 9694-9694/app.kemura.aac_studies I/System.out: 6
2019-03-25 21:42:40.458 9694-9694/app.kemura.aac_studies I/System.out: observeForever : 6
2019-03-25 21:42:41.461 9694-9694/app.kemura.aac_studies I/System.out: 7
2019-03-25 21:42:41.461 9694-9694/app.kemura.aac_studies I/System.out: observeForever : 7
2019-03-25 21:42:42.464 9694-9694/app.kemura.aac_studies I/System.out: 8
2019-03-25 21:42:42.464 9694-9694/app.kemura.aac_studies I/System.out: observeForever : 8
2019-03-25 21:42:43.467 9694-9694/app.kemura.aac_studies I/System.out: 9
2019-03-25 21:42:43.468 9694-9694/app.kemura.aac_studies I/System.out: observeForever : 9
2019-03-25 21:42:44.468 9694-9694/app.kemura.aac_studies I/System.out: 10
2019-03-25 21:42:44.468 9694-9694/app.kemura.aac_studies I/System.out: observeForever : 10
```

→onDestroyされるまでカウントアップする

## 課題8.1

```
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Transformations.map
        Transformations
            .map(CountUpLiveData()) {
                it * it
            }
            .observe(this, Observer {
                println(it)
            })
    }
```

結果

```
2019-03-25 21:46:02.888 10063-10063/app.kemura.aac_studies I/System.out: 1
2019-03-25 21:46:03.889 10063-10063/app.kemura.aac_studies I/System.out: 4
2019-03-25 21:46:04.892 10063-10063/app.kemura.aac_studies I/System.out: 9
2019-03-25 21:46:05.894 10063-10063/app.kemura.aac_studies I/System.out: 16
2019-03-25 21:46:06.898 10063-10063/app.kemura.aac_studies I/System.out: 25
2019-03-25 21:46:07.901 10063-10063/app.kemura.aac_studies I/System.out: 36
2019-03-25 21:46:08.901 10063-10063/app.kemura.aac_studies I/System.out: 49
2019-03-25 21:46:09.904 10063-10063/app.kemura.aac_studies I/System.out: 64
2019-03-25 21:46:10.906 10063-10063/app.kemura.aac_studies I/System.out: 81
```

# チャレンジ課題

## 9.1

```
    private fun mediator() {
        MediatorLiveData<Int>()
            .apply {
                val source = CountUpLiveData()
                addSource(source) {
                    if (it < 10) {
                        value = it * it
                    } else {
                        removeSource(source)
                    }
                }
            }
            .observe(this, Observer {
                println(it)
            })
    }
```

結果

```
2019-03-25 21:58:01.347 11132-11132/app.kemura.aac_studies I/System.out: 1
2019-03-25 21:58:02.350 11132-11132/app.kemura.aac_studies I/System.out: 4
2019-03-25 21:58:03.353 11132-11132/app.kemura.aac_studies I/System.out: 9
2019-03-25 21:58:04.355 11132-11132/app.kemura.aac_studies I/System.out: 16
2019-03-25 21:58:05.358 11132-11132/app.kemura.aac_studies I/System.out: 25
2019-03-25 21:58:06.361 11132-11132/app.kemura.aac_studies I/System.out: 36
2019-03-25 21:58:07.363 11132-11132/app.kemura.aac_studies I/System.out: 49
2019-03-25 21:58:08.370 11132-11132/app.kemura.aac_studies I/System.out: 64
2019-03-25 21:58:09.374 11132-11132/app.kemura.aac_studies I/System.out: 81
```

## 課題10.1
ちょっとあとでやる

# ViewModel

## 課題11

```
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val viewModel1 = ViewModelProviders.of(this).get(MainViewModel::class.java)
        val viewModel2 = ViewModelProviders.of(this).get(MainViewModel::class.java)

        println("viewModel1 : $viewModel1")
        println("viewModel2 : $viewModel2")
    }
```

```
2019-03-25 22:02:12.866 11452-11452/app.kemura.aac_studies I/System.out: viewModel1 : app.kemura.aac_studies.MainViewModel@be7832
2019-03-25 22:02:12.866 11452-11452/app.kemura.aac_studies I/System.out: viewModel2 : app.kemura.aac_studies.MainViewModel@be7832
```

## 課題12.1