DroidKaigi 2019のセッションで個人的に驚いたところメモ

去年や一昨年は自分が発表していたので資料作っちゃってて書けなかったんですが、今回はFiresideChat以外はフルで参加出来たのでまとめておきます。

といっても自分のTwitterのメモを振り返るだけで、しかも本筋に沿ったところはあんまりメモせず、自分がおおって思ったところだけです :bow: 
かなり驚いたり、すぐに使えるみたいなやつを太字にしています。

# マルチモジュールなプロジェクトでテストはどう変わる？
資料: https://speakerdeck.com/tkmnzm/how-change-testing-in-modular-architecture
Project Nitorogenのロードマップが存在する
![image.png](https://qiita-image-store.s3.amazonaws.com/0/27388/3a49d013-f528-3d99-2283-12f4d88d9197.png)

ちなみにProject Nitorogenは

> Project Nitrogen はそれぞれの実行環境での単一のエントリーポイントとなり、テストの収集から実行環境のセットアップ、テストの実行、レポートまで、統一して扱えるプロトコルを提供するようです。

だそうです (https://medium.com/mixi-developers/android-test-%E3%81%AF-write-once-run-everywhere-%E3%81%AE%E5%A4%A2%E3%82%92%E8%A6%8B%E3%82%8B%E3%81%8B-4b6e179928f6 より)

**PITというライブラリ**
Mutation Testingというプロダクションコードを機械的にif文の中身などを変更してテストできる。これを使うとテストケースでカバーできていない部分を教えてくれる。
これは自分の理解ですが、以下みたいな`if`文があったとして、

```kotlin
if (session.room == HallA) {
  ...
}
```

これを`PIT`だと勝手に書き換えて、その時にテストケースを走らせて、ちゃんとテストが失敗するようになっているかをチェックして、ちゃんとテストで色んなパターンが網羅されているかを教えてくれるイメージです。

```kotlin
if (session.room == HallB) { // HallBに書き換えられた
  ...
}
```

# マルチモジュールプロジェクトでのDagger2を用いたDependency Injection
資料: https://speakerdeck.com/kgmyshin/android-multi-module-with-dagger
Dagger Androidのモチベーションは、Injectされる側が何をInjectされるか指定してしまっているのを解決する。
例えば

```kotlin
class MainActivity: Activity() {
  fun onCreate(..) { 
    // ここでInjectされる側が詳細を知ってしまっている。
    (application as App).appComponent.inject(..)
  }
}
```

AndroidSupportInjector.inject(this)を呼んだ時に、HasSupportFragmentInjectorをthisが継承しているかチェックして、していなければActivityでチェック、していなければApplicationでチェックしに行く。

# LiveData と Coroutines で実装する DDD の戦術的設計
資料: https://y-anz-m.blogspot.com/2019/02/droidkaigi-2019-livedata-coroutines-ddd.html

Kotlin Multi PlatformでモデルにString Resourceを入れられない場合に
**Enumにextension functionを生やしてstring resourceを取得する**
便利！(どこに置くか悩むという課題はありそう ui.modelextension。。みたいな。。？)

自分の脳内イメージ

```kotlin
enum class Room{
  HallA, HallB ...
}
```

```kotlin
val Room.textResource get() = when(this) {
     HallA -> R.string.timetable_room_hallA
     ...
  }
```

LunchとかはSessionじゃないのでTimeTableItemを作ってそれを継承させたりなど名前にちゃんとこだわる。フィールドもレスポンスなどにあっても使っていなければ徹底的に削る(言われてみるとたしかにという感じ)

# Master of Android Theme

資料: https://speakerdeck.com/konifar/master-of-android-theme

**.Bridgeで終わるテーマはAppCompatを継承したテーマで、これを使うことで、今AppCompatを使っているアプリもアプリのテーマを変えずにMaterialComponentを使える！！**

テーマで色を変えるアプリの例はこれ(これに関してサンプルコードもあるかと思ったけど、無さそう？)
https://material.io/design/material-studies/owl.html#

テーマのAndroidフレームワークの各ライブラリの対応状況が見られる。
https://github.com/konifar/android-theme-attrs-to-markdown-table

Material ComponentではcolorPrimaryDarkがcolorPrimaryVariantになった。
colorOnPrimaryでPrimaryColorのバックグラウンド上のアイコンの色を指定できる。
Widgetのスタイルを変更するには"xxStyle"補完する(toolbarStyleなど)。そして例えばtoolbarではWidget.AppCompat.Toolbarを探す。それでどんな設定ができるかわかる。 
ShapeAppearance : 形を変える 大きさによって適応するの変えられるSmallに適応するとChipとかだけ角が削れているなど。

# R8、Proguard徹底比較
資料: https://speakerdeck.com/satoshun/proguard-che-di-bi-jiao
**R8はD8(元Dex)とProguardが一緒になったもの。**(Proguardの置き換えだと思っていました！)
addconfigurationdebugging、クラッシュした時にkeepの設定を提案してくれる設定(知らなかった) R8では今は使えない
**identification、(Proguardのみ？)難読化した時にリフレクションの文字列の方も書き換えてくれる。すごい**
assumevaluesを使うとminsdkによってbuild.sdkのif文の分岐を消せたりできる(勝手に有効になっている) 
dexdumpを使うとdexを人間が読める形にしてくれる

* iputのiはインスタンス
* sgetのsはstatic

companion objectがR8で消える。なるべくstaticメソッドなどに変換する。
Kotlinのラムダ式はラムダごとにクラスが作られる。R8だとラムダグループという最適化で、1つのクラスのフィールドに格納してくれる。

# Fireside chat

もゆるさんのLayoutManagerの話

どどうやって作るか？

* まずViewを全部レイアウトしちゃうように作る。
* その後に画面外のViewを消すようにして、逆にスクロールで空いた場所に(例えば下にスクロールしたら下に隙間ができる)Viewを入れるようにする
* scrollToPositionは位置をメンバ変数に保存しておいて、requestLayoutする

# Not Just Rotation: Configuration Changes on Android
(Googlerのセッション)

Configurationとは？Orientation、画面のサイズ、画面のレイアウト(丸とか、左右の逆)、フォントの大きさ(spを使うと変わる)、pixel density、UI Mode(TV, VR, NightMode) (一部)
どんなときにconfig changeするか？画面回転、マルチウインドウ、Picture-in-Picture、Multi-Display(プロジェクターに映すとか)、Folding(フォルダブル)

どうconfig changesに対応する？

* 何もしないとListViewが上に戻ったりとかするかも？
* SaveInstanceStateのデメリットはステートの数とステートの型に制限がある。また遅くなる。
* ViewModelだとプロセスをまたいで生き残ることが出来ない。その場合は保存する必要がある。

**Manifestでandroid:configChangesで設定した時にどうやって対応するか？**
**onConfigrationChangedメソッドでsetContentViewする**

```kotlin
override fun onConfigurationChanged(newConfig: Configuraiton) {
  if (newConfig.screenLayout != config.screenLayout) {
    setContentView(R.layout.activity_main)
    setSupportActionBar(findView...)
    if(...)supportActionBar?.hide()
  }
}
```

* configuration changeをハンドリングする場合はエッジケースがどんな場合があるのかわかっておく必要がある。ただあらゆることが変わり得る。ViewModelだと楽。(ただハンドルするのも全くなしでは無さそうな雰囲気)

# Gradle BOM importでライブラリバージョン管理
資料: https://speakerdeck.com/gya/droidkaigi2019

こんな感じで書くと、Bomファイルに書いてあるバージョン情報を使う。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/27388/f288494e-9f3d-008e-cadf-4a3b231b96d3.png)

**BOMはこんな感じのファイルをダウンロードすることで、一つのBOMファイルインポートでいろんなライブラリのバージョンを揃えることができるできる**(BOMのimportだけでは依存関係は入ってこない) まだ対応しているライブラリは少ない。
https://bintray.com/bintray/jcenter/download_file?file_path=com%2Fsquareup%2Fokhttp3%2Fokhttp-bom%2F3.12.1%2Fokhttp-bom-3.12.1.pom
BOMの設定を優先させたり、ライブラリの設定で設定したほうを優先させたりできる。

# Deep dive into MotionLayout
資料: https://www.slideshare.net/hagikuratakeshi/deep-dive-into-motionlayout

<OnClick motion:target= でクリックしたときの動きとかできる
MotionLayoutで指定するConstraintSetでViewのプロパティをいじれる。例えば色を始まりと終わりで指定するとアニメーション中にその間の色を勝手にセットしてくれる
KeyPotiionでアニメーション途中の状態を定義できる。左右にずらす時に上に間に上にずらさせたりできる。いろんなプロパティが使える(KeyAttributesという + カスタムアトリビュートも使える <CustomAttribute motion:attributeName="Background"みたいな)
KeyTimeCycleを使うとProgressにしばられない時間で繰り返すアニメーションもできる！
**Introducing CycleEditor! 初出。めっちゃアニメーションいじれる**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/27388/2bbdb740-9e58-b3bf-037b-b14a5be59154.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/27388/01c40cd9-7b0c-d83e-c5ff-bdf7624352ea.png)
https://github.com/googlesamples/android-ConstraintLayoutExamples/tree/master/CycleEditor/src/com/google/androidstudio/motionlayoutcycles

MotionLayoutはViewPagerとも使える (DroidKaigiのタブとかもこれでも良かったかも)
state1 <-> 最初の状態 <-> state2 みたいにできる。
KeyTriggerを使うとスクロールの10%からFabのshow()を呼んで20%からhide()を呼んだりできる。
MotionLayout Alpha4 resize handling, View visibility, Attribute rename, **RecyclerView** ← !?
MotionLayoutでRecyclerViewから詳細へのSharedElementTransitionっぽいのができる！

# Android Studio設定見直してみませんか？
資料: https://shiraji.hatenablog.com/entry/2019/02/08/131843

* QuickListをPreference>QuickListsで+ボタンでActionを追加していって、`Split Window` とか、`コミット` とかのアクションを追加していける、自由に追加できる。そのQuickListsにKeybindをふれる。良さそう
* FileColorでScopeをProductionにして色を設定するとそのバリアントで入るフォルダだけをハイライトできるので、変な場所をいじらないで済む
* **inspections > KotlinでFile is not formatted..をエラーに設定するとフォーマットしていない時にエラー表示ができる。** ← これデフォルトでONにして欲しいレベル。。
* デバッガー > コンディション > confirm removal of ...でブレークポイントに条件が入っているときに消そうとしたら警告してくれる
* 文字列をjsonとして扱うようにすると勝手に@ Languageアノテーションをつける機能がある

(Tweetで別セッションで`adb lolcat`でもlogcat出してくれそうなことを知る)

# Lifecycle, LiveData, ViewModels - The inner wiring

onPauseの場合はonPauseイベントが発火して、その後にActivityなどのonPause()メソッドが呼ばれる。onCreateなどは逆。
Fragmentのライフサイクルはライフサイクルが2つある FragmentのライフサイクルとFragmentのViewのライフサイクルがある。
**Fragment.viewLifecycleOwnerLiveDataを使ってFragmentのViewのライフサイクルのLiveDataが取れる**
今のライフサイクルを知るだけであればFragment.viewLifeCycleOwnerで取れる(基本こっちで良さそう)
**FragmentのライフサイクルはFragmentのViewのライフサイクルより長いから viewLifecycleOwnerLiveDataはLiveData<LifecyclerOwner>を返す。**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/27388/cb2b01a7-fd9e-5ef4-699c-a815b4f4613e.png)

LiveDataでmergeをどうやって実装するか？MediatorLiveData使おう。
RxJavaとの違い、RxJavaはデータホルダーでない、LiveDataには終わりのイベントがないなど。
ViewModelはバックボタンなどでは普通に消える。

# Journey of APK from compilation to launch 
aapt : Android Asset Packaging tool. R.javaを作る。
R.javaの数字の法則性
0xPPTTNNNN
0x7fは決まっている。
**その次の2数字TTはカテゴリでdrawableとかを示す。**
その後が前のものの次のものが採番される。

ZipAlign: メモリアラインメント。CPUレベルでリードライトされるが、4バイトごとに行われる。4バイトごとにデータをずらしたりするっぽい

# Fast Prototypes with Flutter + Kotlin/Native
資料: https://tech.olx.com/fast-prototypes-with-flutter-kotlin-native-d7ce5cfeb5f1

APIとかいろいろKotlinで共通化しているっぽい。
(Kotlin MPPで作ったモデルがFlutterで使えないっぽいのでメソッドチャンネルで渡すのがちょっとつらそう。)

# 実践 WorkManager
資料: https://speakerdeck.com/_atsushisakai/workmanager
WorkManager Workerは冪等性を担保する必要がある。失敗しても大丈夫なように何度動いても大丈夫なようにする。
WorkManager デフォルトで指数関数的に伸びる。数日後にいきなり呼ばれたりする。
getRunAttemptCountでretry回数は自分で見てRETRYをとめる。
Workerの名前を変えたりコードをアップデートするとエラーになったりする(怖い)。Workerは10分でタイムアップする。Workerの単位を小さくして処理をチェーンするようにする。
cancelを呼んでも動いているworkerは止まらない。onStoppedをオーバーライドすることでcancel時の挙動を書ける。
QAのためにデバッグ画面で動いているJOBがみられるようにする。
**WorkManagerはRobolectricによるテストに対応しないとIssue trackerに書かれている**
WorkManager: We never supported Robolectric

# Android アプリ開発における、デザイナーとエンジニアのワークフロー
Androidでどのコンポーネントが使えるかをデザイナに共有することで、開発を効率的にしよう。
デザインをする時にSketch上でmaterial theme editorを使ってもらうと色や角が切れているデザインなどを一気に変えたりできて、かつAndroidのコンポーネントと整合性があるので使ってもらおう。


# まとめ
参加したすべてのセッションで学びがありました！最高のイベントでした！