R8でコードシュリンクしつつInstrumentation Testをやる
いろいろハマってしんどかったので雑にまとめておく。
ことの顛末
- Instrumentation Testのテストが全然動かない。テストがないとか言われる
- Logcatをみると
DaggerTestAppComponent
をDaggerAppComponent
にキャストできませんとか言われている。そらそうよ - ちょっと書き換えると今度は
kotlin.reflect.KProperty0
がないとか言ってくる。なんでや - キャストするコードは書いていない。明にキャストしたり、安全キャスト(
as?
)をやったりしてみるがなぜかDaggerAppComponent
にキャストされようとしてクラッシュする。Kotlinバイトコードをデコンパイルしてみても特に変なところはない。dexにする段階で何か変わってしまったのか?と思ってapkファイルの中のバイトコードを確認すると、check-cast
という命令が追加されており、ここでDaggerAppComponent
型かどうかのチェックがされていた。 - R8の最適化が効いたのかな?と思って最適化させない命令(
-dontoptimize
)を付けると今度はkotlin.reflect.KProperty0
が無いといわれる。またか。だがdexのバイトコードにはcheck-cast
がなくなっていた。 - そうかそれならってことで今度は
-keep
でkotlin.reflect
以下のクラスを残すことにした。すると今度は別のクラスが無いという話になったので、一応効いているということが分かった。ないといわれたクラスを片っ端からkeepで残すことにしていったらテストが動くようになった。
敗因
SavedStateHandleを使ってLiveDataの値を保存する
ViewModel
が持っているLiveData
の値をインスタンスステートとして保持したいとき、androidxのlifecycle-viewmodel-savedstate
ライブラリを使う。fragment 1.2.0
やactivity 1.1.0
を入れているとその依存関係としてsavedstateも入ってくる*1。この記事ではlifecycle-viewmodel-savedstate 2.2.0
での挙動を前提とする。
本当はDIを使ってViewModel
にSavedStateHandle
を注入するところまでが大変なのだが、いろんなブログや本に書いてあるので割愛する。タイトルの通りLiveData
の値を保存したいときはまず、ViewModel
に注入されたSavedStateHandle
からgetLiveData()
を使ってMutableLiveData
を取り出す。
val data: MutableLiveData<Hoge> = savedStateHandle.getLiveData("key_data")
こうすると、SavedStateHandle
内部に定義してあるSavingStateLiveData
というクラスのインスタンスが内部キャッシュから返されるか、そこになければ生成される。このSavingStateLiveData
はsetValue()
の都度、SavedStateHandle.set()
相当の処理をやってくれる。つまり、上で書いたdata
に対しては
data.value = someHogeValue // postValue()も大丈夫なはず
をやるだけでよい。これでいつonSaveInstanceState()
が呼ばれても大丈夫。いうまでもないが、LiveData
以外のプロパティに対しては別途対応が必要になる。
danger-kotlinをやっていこう
DangerfileをKotlin scriptで書けるというので試してみている。今の時点ではver. 0.5.1でWIPとのこと。
Github Actionsで実際に動かしてみているのだが、これまでDangerで使っていたようなプラグインが使えるようにはなっていないようで、今のところ簡単ではない。それでもkotlin力(ちから)に自信があれば自分でプラグインを書いてもよいと思う。
DangerfileをKotlin scriptで書くにあたり、コードの自動補完が効くようにしたい。開発環境がMacOSやLinuxの場合はREADMEに書いてある通りに進めればいいのであろうが、私はWindowsで作業しているので少々難儀した。
READMEにはまず最初にdanger-kotlinをマシンにインストールせよと書いてあるので、Makefileを読みビルドの手順をWindowsに置き換えて実行しようとしたのだが、Windowsだとビルドが通らないようになっていた。その後少々考えて、ダメ元でWSL2の上でJarをビルドし、これに対してパスを通したところ、自動補完が効くようになった*1。
あとはKotlin scriptの設定がどこにあるか分からなかった。Android Studio 4.0では設定のOther Settings > Kotlin compilerの下の方に目当てのものがある。
プラグインをどうにかしたい。gradleでjrubyやgemを使えるようにするプラグインはあるので、Kotlin scriptでも何とかして似たようなことができないだろうか。無職になり有り余る時間ができてしまったので挑戦してみてもいいかもしれない。
*1:インタフェースはちゃんと見えているから自動補完だけなら大丈夫ということだろうか