最近のJetpack Compose事情

Jetpack Compose も dev から alpha になり、2020/11 現在の Compose はどのようになっているのか、書いていこうと思います。


- 公式ドキュメント (https://developer.android.com/jetpack/compose)
- チュートリアル (https://developer.android.com/jetpack/compose/tutorial)
- サンプルアプリ (https://github.com/android/compose-samples)

## State
- `remember {}` と State で状態を管理
- State の値が変わることで Composable を再描画
- `remember { mutableStateOf() }` の代わりに `savedInstanceState {}` を使うことで画面回転時にも値を復元できる

```kotlin
val mutableState = remember { mutableStateOf(default) }
var value by remember { mutableStateOf(default) }
var value by savedInstanceState { default }
```

## レイアウト
- Box、Column、Row での基本的なレイアウトや LazyColumn でのリスト表示や Constraint が用意されている
- タップイベントや padding 、 align などのレイアウトに対する指定は `Modifier` で行う
    - dev の初期は padding も Composable でしたが、ネストが深くなるのでこの方法に変わっている
- ViewPager や MotionLayout の Compose 版はまだない  

```kotlin
@Composable
fun Example(
    onClick: () -> Unit
) {
    Column(
        Modifier
            .clickable(onClick = onClick)
            .padding(16.dp)
            .fillMaxWidth()
    ) {
        Row(verticalAlignment = Alignment.CenterVertically) { … }
        Spacer(Modifier.preferredSize(16.dp))
        Card(elevation = 4.dp) { … }
    }
}
```

## Navigation
- [Navigation Compose](https://developer.android.com/jetpack/androidx/releases/navigation#navigation_compose_version_100_2) が登場し、これまでの Jetpack Navigation を Compose でも使える  
    - [Navigation Compose を使ってみる](https://qiita.com/Nabe1216/items/f329e981f0da76c1d221)

```kotlin
@Composable
fun App() {
    val navController = rememberNavController()
    NavHost(navController, startDestination = "profile") {
        composable("profile") { Profile(...) }
        composable("friends") { Friends(...) }
    }
}

@Composable
fun Profile(navController: NavController) {
    Button(onClick = { navController.navigate("friends") }) {
        Text(text = "Navigate next")
    }
}

```

## Paging
- [Paging Compose](https://developer.android.com/jetpack/androidx/releases/paging#paging_compose_version_100_2) が登場している

```kotlin
@Composable
@OptIn(ExperimentalLazyDsl::class)
fun ItemsDemo(flow: Flow<PagingData<String>>) {
    val lazyPagingItems = flow.collectAsLazyPagingItems()
    LazyColumn {
        items(lazyPagingItems) {
            Text("Item is $it")
        }
    }
}
```


## Material Component
- これまでの Material Component にあった Component もほとんど用意されている
- Jetpack Compose にはこれまでの Material Component にはなかった Backdrop が用意されている  
- Material Theming の仕組みも Jetpack Compose でそのままに用意されている
    - DarkTheme ももちろん対応
- [material-components-android-compose-theme-adapter](https://github.com/material-components/material-components-android-compose-theme-adapter) という xml で定義していた theme をそのまま Compose で使うライブラリもある
- Motion system の Compose 版はまだない　　
- `material.icons` パッケージにアイコンが用意されているので、リソースに追加しなくても Compose でアイコンが使える
    - ちなみにこのアイコンはコードにパスデータを持っている

```kotlin
@Composable
fun AppTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable() () -> Unit) {
    val colors = if (darkTheme) {
        DarkColorPalette
    } else {
        LightColorPalette
    }

    MaterialTheme(
        colors = colors,
        typography = typography,
        shapes = shapes,
        content = content
    )
}
```

## Android Architecture Component の ViewModel や LiveData

- Composable の中で `viewModel()` 関数を使うことで ViewModel を取得できる
- `LiveData.observeAsState()` で State に変換して受け取ることができる

```kotlin
@Composable
fun Example() {
  val viewModel: ExampleViewModel = viewModel()
  val value: String by viewModel.value.observeAsState("initial")

  Text("Value is $value")
}
```

## kotlin-coroutines
- ~~`LaunchedTask` (1.0.0-alpha07 で deprecated に)~~ `LaunchedEffect` のブロックが suspend fun になっている
- `Flow.collectAsState()` で State に変換して受け取ることができる

```kotlin
val value: String by stateFlow.collectAsState()
Text("Value is $value")
``` 

## RxJava2
- `Observable.subscribeAsState()` で State に変換して受け取ることができる
    - もちろん `Single` や `Completable` などにも対応

```kotlin
val value: String by observable.subscribeAsState()
Text("Value is $value")
``` 

## 画像読み込み
- [accompanist](https://github.com/chrisbanes/accompanist) に Coil、 Glide、Picasso を使って画像を表示させるライブラリがある


## これまでの View との互換
- Composable の [AndroidView](https://developer.android.com/reference/kotlin/androidx/compose/ui/viewinterop/package-summary#androidview) を使うことでこれまでの View を Composable の中でも使うことができる

```kotlin
// Compose a TextView.
AndroidView({ context -> TextView(context).apply { text = "This is a TextView" } })
// Compose a View and update its size based on state. Note the modifiers.
var size by remember { mutableStateOf(20) }
AndroidView(::View, Modifier.clickable { size += 20 }.background(Color.Blue)) { view ->
    view.layoutParams = ViewGroup.LayoutParams(size, size)
}
```
- `ComposeView` を xml で使うことで View・Fragment 単位での Compose の利用ができる

## その他
- accompanist には [WindowInset の Jetpack Compose サポートのライブラリ](https://github.com/chrisbanes/accompanist/blob/main/insets)も用意されている
- Lottie の [Compose 対応版](https://github.com/airbnb/lottie-android/releases/tag/compose-v1.0.0-alpha01)も出ている
- Compose のプレビュー機能も充実してきている
    - [Jetpack Compose の Preview を使いこなす](https://qiita.com/Nabe1216/items/84f842f5579e17bef0be)
- [Compose for desktop](https://www.jetbrains.com/lp/compose/) が登場し、Compose で Desktop のアプリも作れる


Compose が alpha になってから様々な既存のライブラリが Compose の対応を始めていたり、Compose 自体もたまにちょっと大き目の変更が入ることがあったりしながら安定性も高まってきていますね。
他にもこれ Compose 対応されてるよという話があったらコメントお願いします :pray: