Open4

Androidアプリ開発をやってみる (Kotlin)

pilefortpilefort

業務でAndroidアプリの開発をすることになったので、学びながら実装していく過程を書いていく。

pilefortpilefort

UIについて

UIの構築方法は2種類
View APIを使う方法と、Compose APIを使う方法。

View API

View APIを使う際はXMLに要素を書く。
XMLに書いた要素にアクセスする際は、idを付与し、idを検索してアクセスする。
こっちの書き方で説明する入門書が多い印象。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout ...>
  <ImageView
    android:id="@+id/img"
    ...
  />
</FrameLayout ...>
// 先にレイアウトファイルを指定する
override fun onCreateView(
  inflate: LayoutInflater,
  container: ViewGroup?,
  savedInstanceState: Bundle?
) : View {
  return inflater.inflate(R.layout.<XML FILE NAME>, container, false)  
}

// 指定したレイアウトファイル内の要素を取得
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  // ...
  val viewImage = view.findViewById<ImageView>(R.id.img)
  // ...
}

Binding

上記のように、findViewByIdを使う方法では、XML上にその要素が存在することを保証できない (実行時エラーになる恐れがある)。

その対応として、Data Bindingという手法がある (こちらを使う場合は存在しない場合コンパイルエラーになる)。
ただ、こちらを利用すると、Compose APIへの移行が面倒になったので、個人的には微妙に感じてる。

Compose API

Googleが推奨する宣言的にUIを構築する方法。
書き方的には、FlutterとかReact Nativeに近い印象で、要素の入れ子を書いていく。

@Composable
private fun Screen() {
    ScaffoldTopAppbar(title = "Home") {
        val modifier = Modifier.padding(it)
        Box(
            modifier = modifier.fillMaxSize().background(Color.White),
            contentAlignment = Alignment.Center
        ) {
            // ...
        }
    }
}
pilefortpilefort

View APIの良いところ

デザインエディターが充実しているため、GUIでUIを構築できる。

UIだけでなく、Navigationも画面間でどのように繋げるかをGUIで記述できる。
そのため、画面ごとにどのような遷移があるかが非常にわかりやすい。

View APIの微妙なところ

layoutファイルはres/layout配下に置く必要があり、ファイルが増えると訳が分からなくなる。
ただし、モジュール化すれば対応できる。

UIの微修正が少々大変。ファイルを行ったり来たりしたり、場合によっては新規ファイル追加が必要になる。

Compose APIの良いところ

UIとロジックが比較的近くにあるため、処理が分かりやすい。
一画面内で要素を切り替えたりするのがやりやすい (フラッシュメッセージとかの実装が割と簡単)。

Compose APIの微妙なところ

Android StudioのDesign Editorが使えないため、GUIで画面を構築したり、Navigationを視覚的に確認したりができない。

UIのプレビューがイマイチ。
引数ありcomposableのプレビューが簡単にできないため、ビルド時には使わないプレビュー用composableの用意などが必要になる。

@Preview
@Composable
fun PreviewCustomButton() {
  CustomButton(text = "preview", ....)
}

// ここに@Previewをつけたいが引数のデフォルト値を設定できないため、プレビューできない。
@Composable
fun CustomButton(text: String, ...) {
  // ...
}
pilefortpilefort

デバッグ

基本はログに出すか、Layout Inspectorで値を見るか。

Timber

Androidの標準ライブラリでログを出力する際は以下のようにする。
これを使う場合、タグ名はここに設定する必要があり、本番ビルド時にもログが出てしまう。

Log.d("<タグ名>", "ログ内容")

Timberを使うと、クラス名がタグ名になるため、記述を省略できる。
また、本番ビルド時にはログを出さないとか、別サービスにログレポートを送ったりできるらしい。

Timber.d("ログ内容")

Layout Inspector