見出し画像

Android の Jetpack Compose を使って良かった点・大変だった点を紹介します #Zaim

こんにちは!
Zaim で Android エンジニアをしてます @bvlion です。

2020 年 8 月 27 日に Android の新ツールキット「Jetpack Compose」のアルファ版(ver. 1.0)がリリースされましたね!

コードで UI をプレビューしながら生成できるのは新鮮ですし、何よりも res 配下の肥大化が防げるのは嬉しく感じます。今回は、そんな Jetpack Compose を Zaim で導入した流れを、お伝えできたらと思います。

環境構築に立ちはだかったエラー 3 選

開発するには当然ながら、まずはビルドが通る状態まで持っていかなくてはなりません。Zaim の環境では、Jetpack Compose を導入するにあたって 3 種類のエラーを乗り越える必要がありました。

Compose UI をプレビューできる Android Studio 4.2 CANARY をインストールして、セットアップドキュメントに沿って Gradle を修正して実行してみます(久々の黄色いアイコンにドキドキしますね!)。

1. java.lang.AssertionError: Unbound symbols not allowed

まず現れたのが「java.lang.AssertionError: Unbound symbols not allowed」でした。どうやら Kotlin Android Extensions が使えないからのようです。この Stack Overflow にもある通り、良い機会なので ViewBinding に置き換えて解決しました。

何となく res/layout のネーミング規約を彷彿とさせますね。

Kotlin Android Extensions…出会った頃は by lazy からの開放に衝撃を受けたものですが、ここでお別れです(涙)。Extensions とは長い付き合いでした。せっかくだから思い出を長く書いて振り返ろうと思ったけれど、そんなになかった…。なお、Kotlin 1.4.20 から非推奨となるようです。

ここで大変だったのは Kotlin Android Extensions が Adapter 系で使われているパターンです。

LayoutInflater.from で取得した View 内のインスタンスを Kotlin Android Extensions で取得している場合、型の再確認が必要なのは骨が折れました。とはいえ幸い Zaim では、対象が 18 クラスにとどまりました。

2. ViewContentsLoadingBinding を ViewDataBinding に変換できません

続いて現れたのは「エラー: 不適合な型: ViewContentsLoadingBindingをViewDataBindingに変換できません」です。

最初は Fragment など、元々 layout タグを付けて DataBinding していた場合に競合するから発生するエラーかと思っていました。しかし調査を進めた所、この記事 にある通り、include したファイルも layout タグで括る必要があることが分かりました。

先行して DataBinding を利用していたクラスですね。こちらもそこまで多くなく、4 ファイルでした。

3. Entry name 'AndroidManifest.xml' collided

最後に「Entry name 'AndroidManifest.xml' collided」にも対応します。
こちらの記事 にある通り、gradle.properties に「android.useNewApkCreator=false」を追加します。Stack Overflow の先人に頼りまくりです。

しかし Zaim では上記で対応した場合、特定の Build Variant で以下のエラーが発生してしまいました。

adb: failed to install app/build/outputs/apk/target/target.apk: Failure [INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: Failed to parse /data/app/hoge.tmp/base.apk: Corrupt XML binary file]

もっと調べてみると、apk を作成した際に AndroidManifest.xml がバイナリになってないのが原因でした。この Stack Overflow の記事の現象ですね。

そこで、競合している AndroidManifest.xml を探して解決します。今回は、とある外部 aar に含まれていた AndroidManifest.xml が元になっていました。これは不要になるライブラリだったので、build.gradle から削除して対応しました。

これで、やっとビルドが通りデバッグが実行できるようになりました!いよいよ開発に入ります。

良かったこと(1)工数・ファイルを減らして実装

まず実装してみて大きく感じたメリットは、実装に必要なファイルが少なくシンプルに済むことでした。

今回は広範囲に影響が出ないように、新規かつ利用頻度が少なそうな画面から適用してみました。アルファが取れた際に大幅な修正が必要になっても問題ないように…と考えると、小さい RecyclerView などに適用するのが良さそうです。

RecyclerView は縦のリストであれば LazyColumnFor で設定できるので、XML の RecyclerView をComposeView に置き換えます。続いてコード側は @Composable アノテーションを付けて実際のデザインを作り、setContent で設定してあげれば完成です!

この程度であれば Adapter を継承したクラスも、行ごとのレイアウトファイルも作らずに実装できました。その分 Activity は少し肥大化したものの、使うポイントを間違えなければ工数も削減できそうですね。

良かったこと(2)プレビューが簡単

また、プレビューがとても簡単に感じました。

XML だと「tools:text」を変えてプレビューしていくことが多いでしょう。コード内で直接データを書き換えてすぐに確認できるので、例えば「文字数が多い場合に折り返しがどうなるか」といったテストが簡単でした。

スクリーンショット 2020-10-16 18.18.46

よくある Model からデータを取得して表示したり非表示に切り替えたり…という場合も、Model の値を変えて即チェックできます。

findViewById を使っていると Model と View のマッピングが正しいかは実際に動かしてみないと分からなかったり、逆に DataBinding を使っているとプレビューでの visiable の切り替え確認が面倒だったりします。どちらも解決できるあたりは、コードですべて実行するからこその利点ですね!

同様に、実機プレビューもとても簡単でした。

この右側の実行ボタンを押下することで @Preview を付与した単位でレイアウトを実機でプレビューできます。

スクリーンショット 2020-10-15 18.08.55

文字サイズなどの実際の表示は実行してみないと分からないもの、いくつか Activity などを遷移した先の機能も含め、確認できるようになりました。

部品をつなぎ合わせるだけでチェックできるので、とてもありがたい機能です!

大変だったこと(1)ドキュメントが不足

今まで知らない機能を使って実装していくので、当然ですが大変だったこともたくさんありました。

一番、困ったのはドキュメントがあまりないことです。開発中は公式ドキュメントを含め、ひたすら Google 検索で情報を得ていたのですが、バージョン 0.1 系の記事がほとんどでした。

例えばタップ時に ripple エフェクトを効かせるには、0.1 では Modifier.ripple() と書くのが正解でした。しかし現バージョンでは、対象のオブジェクトを MaterialTheme で囲むことで機能します。

今回、利用した LazyColumnFor も名称が違っていたりと、旧仕様なのか現行仕様なのかの見極めには時間がかかりました。

大変だったこと(2)機能が不十分

まだアルファ版ということもあり、まだ対応が間に合ってなさそうな機能がいくつかありました。例えば padding などに設定する dp に関しては dimensionResource から取得できた一方で、sp は残念ながら見当たりませんでした(もっと探せばあるのかも…)。

なので Density.kt を参考に、以下のような関数を作り対応しました。

@Composable
fun dimensionSpResource(@DimenRes id: Int): TextUnit {
  val context = ContextAmbient.current
  val density = DensityAmbient.current
  val pxValue = context.resources.getDimension(id)
  return (pxValue / (density.fontScale * density.density)).sp
}

実際のコードでは Column の下に Row が二つあり、Row の中には Text と Image が…のようなよくある構成でも、ネストは深くなりがちです。

それ自体は XML でも同様ですが、せっかくコードでメソッド分できるので、上手に分けていくと良さそうでした。テキストなど padding が設定されている共通部品クラスなどがあっても良いかもしれませんね。

大変だったこと(3)プレビューが不正確

プレビューがイマイチ、言うことを聞いてくれませんでした…。

以下のキャプチャでは矢印画像を右寄せにして、縦は中央寄せとしたい例です。書き方の問題なのかもしれませんが、少しずれた場所に表示されてしまいます。実際に実行すると、右側にある四角の枠内に表示されます。

スクリーンショット 2020-10-11 15.46.42

これは、これから改善されていくのかもしれません。

大変だったこと(4)マシンパワーが必要

​物理的なところでいくと、プレビューではとにかく PC が唸ります。

Android Studio 自体がもっさりとして、レインボーカーソルが表示されることもしばしば。メモリは 16GB じゃ足らないんでしょうか…?

終わりに

まだアルファ版ということもあり事例は少ないですが、簡単な表示であれば導入しても良さそうだと感じました!

ただ Android 11 Meetups でも発表されていましたが、まだ数年は XML がメインになるとのことでしたので、導入箇所の見極めは大切そうです。

まずは、アルファが取れるところから順に随時アップデートがあるはずなので、定期的に情報を追っていきたいと思います。

最後の最後に…

Zaim では今回のような Android を始めとして、iOS やサーバーサイドなどでも最新技術を駆使しながらサービス発展に挑戦しています。

もっと詳しい内容を聞いてみたい場合は「話を聞いてみたい」をポチっとしてみてください。今すぐ転職したいわけじゃない方も、大歓迎です!


この記事が気に入ったら、サポートをしてみませんか?
気軽にクリエイターの支援と、記事のオススメができます!
9
業務では Android をメインに、一部サーバーサイド(PHP)の対応もさせていただいております<(_ _)>

こちらでもピックアップされています

Zaim スタッフの頭の中
Zaim スタッフの頭の中
  • 94本

「毎日のお金も、一生のお金も、あなたらしく改善。」をコンセプトに家計簿サービスを運営する株式会社 Zaimです。中のスタッフたちが、どんな風にサービスに向き合い働いているかを綴る note です。

コメントを投稿するには、 ログイン または 会員登録 をする必要があります。