6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

JetpackComposeって、どうなん?

Posted at

JetpackComposeって、どうなん?世の中普及具合

去年の夏ぐらいからAndroidアプリ開発者としてデビュー。1年とちょっとになります。
Androidアプリ開発の世界の色々なことが徐々に見え始めたのと、当時は何もない白紙の状態からのスタートだったのでView方式(Layout.xml、Activity、Fragment)から始めました。

昨今になって、JetpackComposeが正式版となってリリースされ、世の中の話題もJetpackComposeの話題が多くなってきたような気がします。
で、もって、世の中のJetpackComposeの普及具合ですが、大手はView方式からJetpackComposeへの移行を進めているようです。

  • メリカリ
  • zozo
  • Retty
  • Wantedly
  • ココナラ
  • 等など・・・

とは行ってもView方式はAndroid1.0がリリースされた2008年、本格的に使われるようになったAndroid2.3の2010年からの膨大な過去の資産があります。

なので、過去に作ったアプリ、色々なドキュメント、書籍はまだまだView方式が多いというのが実情です。

  • Fragmentの導入(Android3.0〜)
  • SupportLibraryの廃止、AndroidXへの移行
  • 等など・・・

逆に、それだけ長い年数、数々の変遷で機能拡張を続けてきた(APIの新設、廃止)こと考えるとView方式はここらで限界を迎えていると言わざるを得ません。

JetpackComposeって、どうなん?何が違うねん?

ざっくり言うと

  • View方式=命令的UI
  • JetpackCompose=宣言的UI

で概念が全く違います。宣言的UIはここ最近WebフロントではやっているReactでも採用されている概念です。

View方式はAndroidStudioの専用デザイナで画面のUIを設計し、ActivityやFragmentからそのUIの部品に対して表示を命令する方式です。
JetpackComposeはComposable部品単位でUIを設計します。Composable部品がComposable部品をネストする感じになります。Composableは状態を監視して(Composable部品の方から状態を取りに行く・・・と言う表現が正しいのか?)状態が変わった場合だけ再表示する仕組みになっています。

Composable部品単位でUIを設計するので、部品の共有はView方式よりもやりやすいのかもしれません。(View方式でもFragmentで共有できないわけでもないが・・・)

なので、View方式でActivity、Fragmentにビジネスロジックを持っていると、そこはかなり変わります。

後述しますが、JetpackComposeにFragmentの概念はありません。(Activityは相変わらずある)Composable部品はみな平等で、階層構造でネストしているので、その中でもトップレベルのComposable部品がFragmentに相当するわけになります。

これも後述しますが、View方式でActivity1個に対して、複数Fragmentで画面遷移するような方式の場合、navigationが使えますが、JetpackComposeもnavigationが使えます。

JetpackComposeは言語はkotlinのみをサポートします。Android開発において、そろそろJava言語とは決別する時期に来ているのかもしれません。

サンプル、codelab

google公式のcodelabがわかりやすいです。

Material2とMaterial3がまだ混在している。

View方式もMaterial2からMaterial3(ボタンが少々丸こくなっている)に変わりつつありますが、JetpackComposeもMaterial2とMaterial3が混在しています。

JetpackComposeのUI部品はpackage的には

  • androidx.compose.material (Material2)
  • androidx.compose.material3 (Material3)

の下に存在しているので、Material2かMaterial3でモノが違います。
Material2とMaterial3でComposable部品の引数が変わっている場合もあるので注意が必要です。

世の中は徐々にMaterial3に移っていくものだと思われます。

Compose でマテリアル 2 からマテリアル 3 に移行する

例 Material2:androidx.compose.material.Scaffold

implementation "androidx.compose.material:material:$m2-version"
@Composable
fun Scaffold(
    modifier: Modifier = Modifier,
    scaffoldState: ScaffoldState = rememberScaffoldState(),
    topBar: @Composable () -> Unit = {},
    bottomBar: @Composable () -> Unit = {},
    snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) },
    floatingActionButton: @Composable () -> Unit = {},
    floatingActionButtonPosition: FabPosition = FabPosition.End,
    isFloatingActionButtonDocked: Boolean = false,
    drawerContent: (@Composable ColumnScope.() -> Unit)? = null,
    drawerGesturesEnabled: Boolean = true,
    drawerShape: Shape = MaterialTheme.shapes.large,
    drawerElevation: Dp = DrawerDefaults.Elevation,
    drawerBackgroundColor: Color = MaterialTheme.colors.surface,
    drawerContentColor: Color = contentColorFor(drawerBackgroundColor),
    drawerScrimColor: Color = DrawerDefaults.scrimColor,
    backgroundColor: Color = MaterialTheme.colors.background,
    contentColor: Color = contentColorFor(backgroundColor),
    content: @Composable (PaddingValues) -> Unit
): Unit

例 Material3:androidx.compose.material3.Scaffold

implementation "androidx.compose.material3:material3:$m3-version"
@Composable
fun Scaffold(
    modifier: Modifier = Modifier,
    topBar: @Composable () -> Unit = {},
    bottomBar: @Composable () -> Unit = {},
    snackbarHost: @Composable () -> Unit = {},
    floatingActionButton: @Composable () -> Unit = {},
    floatingActionButtonPosition: FabPosition = FabPosition.End,
    containerColor: Color = MaterialTheme.colorScheme.background,
    contentColor: Color = contentColorFor(containerColor),
    contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets,
    content: @Composable (PaddingValues) -> Unit
): Unit

JetpackComposeって、どうなん?View方式のアレは何に代わった?

Fragment

Fragmentはなくなっています。View方式の場合はFragmentのクラスとLayout.xmlが1対1でしたが、Layout.xmlも無くなっているので、何がFragmentに相当する?と言われると、@Composableの階層構造の部品の中でもトップレベルがFragmentに相当するという解釈があっているのかなと思います

RecyclerView

RecyclerViewも無くなっています。View方式の場合はRecyclerView.Adapterを継承したクラスとViewHolderクラスが必須ですが、そんな概念もなくなっています。
RecyclerViewは

  • LazyRow(横方向)
  • LazyColumn(縦方向)

に変わっています。

ActionBar、Toolbar

アプリの上部に表示されるActionBar、Toolbarも無くなっています。
ActionBar、ToolbarはScaffoldの引数のtopBarに変わっています。
topBarもComposable部品なので、Composable部品を組み合わせて構成することになります。View方式のようなmenu.xmlはありません。

Navigation

View方式もJetpackComposeも画面遷移にNavigationは使えますが、仕組みは全く違います。

JetpackComposeのNavigationはcodelabが参考になります。

ViewModel

ViewModelはView方式と同様使えますが、立ち位置が少々違います。AACにおいて、View方式の場合は画面の一部の情報の状態保持と、Repositoryとの中継(room、HTTP送受信など)にも使われていました。

画面の一部の情報の状態保持はJetpackComposeの場合はremember関数を使います。remember関数を使うことによって、Composeに状態が監視され、状態が変わるとそのCompose部品が再表示されます。

ViewModelはそれ以外の、Repositoryとの中継(room、HTTP送受信など)に使われます。

remember関数も種類がたくさんあります。
remember関数の説明についてはこれが一番、わかりやすかった。

coRoutine

coRoutineもView方式同様、JetpackComposeでも使用されます。
ViewModelの中から使われる場合はscopeは今まで通りviewMoeelScopeでよいですが、Composable部品のAnimetion等にもcoRoutineが使われますので、Composable部品の中からscopeの取得が必要です。

val scope = rememberCoroutineScope()

Room

RoomはView方式同様使えます。RoomはViewModelの中のRepositoryから呼ばれるケースが多いと思うのでそこは変わりません。
View方式でRoomを全件、複数件検索するObserverパターンはViewModelでStateFlowで返す必要があります。

Layout系

UIを定義するLayout.xmlがないので

  • ConstraintLayout
  • LinerLayout
  • FrameLayout
  • TableLayout
  • 等など・・・

は存在しません。レイアウトはPreviewで確認しながら、Modifierで頑張るしかありません。
この辺はView方式より劣るところです。

UIのテスト

Androidアプリのテストですが、

View方式の場合、テストフレームワークは以下の3つありました。

  1. Espresso
  2. Robolectric
  3. UI Autometer

UI AutometerはE2Eテストなので、JetpackComposeでも変わりません。

公式のcodelabのJetpackComposeのUIテストはInstrumentTestになります。
View方式の場合はRobolectricによるUIテストはlocal Testでできましたが、InstrumentTestになると実行時間が余計にかかります。

以下の資料によるとJetpackComposeでもRobolectricでのLocal Testはできるように書かれていますが、一体どうやってやるのか?サンプルがあれば見てみたいところです。

Junitテストフレームワークは未だにJunit4のようです。(何故、JUnit5に移行しないんだ?)

androidTestImplementation "androidx.compose.ui:ui-test-junit4"

build.gradle.ktsではespressoを依存関係に入れていますが、createComposeRuleがespressoに依存している(内部で呼び出しているのか?)かどうか、よくわかりません。

Droidkaigi 2023ネタ

Droidkaigi 2023のセッションでも似たような話題がありました。

JetpackComposeって、どうなん?まだ、不足しているところ

専用デザイナがない

View方式の場合はAndroidStudioにlayout.xmlを編集できる専用デザイナがあり、その専用デザイナから部品をConstraintLoyoutにポイっとDrag&Drop
して配置を決めれば、それなりに画面デザインできましたが、JetpackComposeにはそのような専用デザイナはありません。UIはすべてコードで書かないといけません。辛うじて、Preview機能はありますがComposable部品単位のPreviewになります。

これはView方式の移行者、新規参入者には厳しいです。上記のようにView方式と同じことを実現する部品自体が変わっていますので、一体、ここで何のComposable部品を使えばいいのか?迷ってしまいます。

ライブラリ

設定画面(View方式の AndroidX Preference)

View方式のAndroidX Preferenceのような、画面を設計する枠組みはまだ標準では用意されていません。

コミニュティのライブラリで、Compose-Settingsがありますが、まだ情報が少くなく、使い方がよくわかりません。
Compose-Settingsの場合は、設定の保存先はSharedPreferencesではなくて、DataStoreを使うのが相性が良さそうです。
(SharedPreferencesでもできるが、googleはSharedPreferencesはobsoluteでDataStoreを推奨している)
このライブラリのui用ライブラリですが、Material2用と3用がありますので注意してください

build.gradle.kts
    implementation("androidx.compose.material3:material3")
    implementation("com.github.alorma:compose-settings-ui-m3:1.0.2") // これ、Material3用
    implementation("com.github.alorma:compose-settings-storage-preferences:1.0.2")
    implementation("com.github.alorma:compose-settings-storage-datastore:0.27.0")
    implementation("com.github.alorma:compose-settings-storage-datastore-proto:0.27.0")
    implementation("androidx.datastore:datastore-preferences:1.0.0")

JetpackComposeって、どうなん?総合的に

JetpackComposeを総合的に見ると、まだまだ不足しているところはありますが、

  • UIの柔軟性がView方式よりある。Composable単位で共通化が可能。
  • 再ComposeはUIに変更があるところだけ実行されるので、実行が早い。端末の負荷が少ない。
  • UIとビジネスロジックの分離がされる。
  • UIもビジネスロジックもkotlinコードで統一される。
  • 宣言的UIなのでWebフロントで流行りのReact等と思考が近い。
  • コード量がView方式より減る(?)。 (これは、View方式のLayout.xmlをステップ数に含めるならそうかもしれない。含めないならJetpackComposeはその分をkotlinコードで書くので逆に増えるのでは?)
  • 大手がView方式から移行を進めている。(^O^)/

などのメリットがあるので、今後はどんどん普及していくのかなと思います。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?