Android
DroidKaigi

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

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

といっても自分のTwitterのメモを振り返るだけで、しかも本筋に沿ったところはあんまりメモせず、自分がおおって思ったところだけです :bow:

かなり驚いたり、すぐに使えるみたいなやつを太字にしています。


マルチモジュールなプロジェクトでテストはどう変わる?

資料: https://speakerdeck.com/tkmnzm/how-change-testing-in-modular-architecture

Project Nitorogenのロードマップが存在する

image.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文があったとして、

if (session.room == HallA) {

...
}

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

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

...
}


マルチモジュールプロジェクトでのDagger2を用いたDependency Injection

資料: https://speakerdeck.com/kgmyshin/android-multi-module-with-dagger

Dagger Androidのモチベーションは、Injectされる側が何をInjectされるか指定してしまっているのを解決する。

例えば

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。。みたいな。。?)

自分の脳内イメージ

enum class Room{

HallA, HallB ...
}

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する

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

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

image.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を返す。

image.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のコンポーネントと整合性があるので使ってもらおう。


まとめ

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