Slide 1

Slide 1 text

Jetpack Compose
 完全に理解した ϞόΠϧνʔϜ ޲ҪాҰฏ

Slide 2

Slide 2 text

Jetpack Compose ってなに? 2 🤔

Slide 3

Slide 3 text

Kotlin でめっちゃええ感じに UI を作るやつ https://developer.android.com/jetpack/compose 3

Slide 4

Slide 4 text

めっちゃええ感じ? Less Code Intuitive 💡 Accelerate Development 🚄 Powerful ⚡ ~.xml は不要になり、Kotlin だけで UI を作成可能 UI を宣⾔するだけ。状態が変化すると UI は⾃動更新 既存のコードと完全に互換。Android Studio がライブプレビュー Material Design, ダークテーマ, アニメーションなどをサポート 4

Slide 5

Slide 5 text

すごそう👏 5

Slide 6

Slide 6 text

Jetpack Compose で
 何が変わる? 6 🤔

Slide 7

Slide 7 text

“Jetpack Compose” 7 🤔

Slide 8

Slide 8 text

Jetpack = Unbundle なツールキット🚀 • Android は OS アップデートの普及が遅い 😨 • Android 9.0 のシェア: 10.4 % • iOS 13 のシェア: 50 % • OS バージョンに依存する API は中々使われない 🤢 • 新しい API を OS アップデートに含めて配布しても使われない 🤮 • Support library → Jetpack 8

Slide 9

Slide 9 text

“Jetpack Compose” 9 🤔 🚀

Slide 10

Slide 10 text

Compose = UI を “構成する” 何か 10 weblio より

Slide 11

Slide 11 text

今までの “UI を構成する” 11 1. データが与えられたとき、何を表⽰するか 2. イベントに対して何をするか 3. UI は時間経過でどのように変化すべきか 4. レイアウトの定義 (my_fragment.xml, attrs.xml, styles.xml )

Slide 12

Slide 12 text

3. UI は時間経過でどのように変化すべきか 12 99+ 10 10 99+ 10 99+ 99+

Slide 13

Slide 13 text

命令型プログラミングで時系列を記述する⾟さ 13 99+ 10 fun updateCount(count: Int) { if (count == 0) { removeBadge() } else if (count <= 99 && hasBadge()) { setBadgeText(count) } else if ... }

Slide 14

Slide 14 text

Jetpack Compose の “UI を構成する” 14 1. データが与えられたとき、何を表⽰するか 2. イベントに対して何をするか 3. UI は時間経過でどのように変化すべきか 4. レイアウトの定義 (my_fragment.xml, attrs.xml, styles.xml )

Slide 15

Slide 15 text

Jetpack Compose 基礎編 15

Slide 16

Slide 16 text

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Greeting("Ippei") } } } @Composable fun Greeting(name: String) { Text("Hello $name") } UI を表⽰する 16

Slide 17

Slide 17 text

UI は関数の組み合わせで構成する • @Composable をつける • Composable 関数は
 データを UI に変換する • データは引数として受け取る • Composable 関数は 
 Composable 関数を呼び出せる 17 @Composable fun Greeting(name: String) { Text("Hello $name") }

Slide 18

Slide 18 text

@Composable fun Greeting(name: String) { if (name == "Ippei") { Text("Hello $name") } else { Text(text = "You are not Ippei") } } @Composable fun Greeting(names: List) { for (name in names) { Text("Hello $name") } } 18

Slide 19

Slide 19 text

19

Slide 20

Slide 20 text

@Composable fun NewsStory(newsItem: NewsItem) { val image = +imageResource(newsItem.imageId) Card(elevation = 2.dp, shape = RoundedCornerShape(4.dp)) { Column(crossAxisSize = LayoutSize.Expand) { Container(expanded = true, height = 180.dp) { DrawImage(image = image) } Column(modifier = Spacing(16.dp)) { Text(text = newsItem.title, maxLines = 2, overflow = TextOverflow.Ellipsis, style = (+themeTextStyle { h6 }).withOpacity(0.87f)) Text(text = newsItem.author, style = (+themeTextStyle { body2 }).withOpacity(0.87f)) } } } } 20

Slide 21

Slide 21 text

UI を更新するときは Composable に新しいデータを渡す 21 Data UI Data UI Composable UI を更新する

Slide 22

Slide 22 text

• ViewModel, LiveData, Rx, Coroutines + Flow • View が ViewModel のデータを継続して購読する 22 Data View (UI) Reactive programming ViewModel Data

Slide 23

Slide 23 text

• @Model を付けたクラスは、観測可能 & スレッドセーフになる • Composable 関数は、Model のプロパティを⾃動で購読 23 @Model Composable UI UI Data Data Model

Slide 24

Slide 24 text

@Model data class LikeButtonState( var count: Int = 0 ) @Composable fun LikeButton( state: LikeButtonState = LikeButtonState() ) { Button( text = "${state.count} Like", onClick = { state.count++ } ) } @Model で状態管理 24

Slide 25

Slide 25 text

Single source of truth * 25

Slide 26

Slide 26 text

View の持つ状態は誰が管理している? 26 誰が View のイベントに反応する? 誰が状態を所有してる? 誰が状態を更新する?

Slide 27

Slide 27 text

android.widget.CheckBox 27 // CheckBox ͸ CompoundButton ͷαϒΫϥε (Java) public abstract class CompoundButton extends Button implements Checkable { private static final String LOG_TAG = CompoundButton.class.getSimpleName(); private boolean mChecked; … // Activity or Fragment (Kotlin) checkBox.setOnCheckedChangeListener { checkBox, isChecked -> // After changed ... checkBox.isChecked = true }

Slide 28

Slide 28 text

android.widget 😩 28 誰が View のイベントに反応する? 誰が状態を所有してる? 誰が状態を更新する? View ではない Listener を実装した誰か 1つの View の状態を複数箇所で所有可能 基本的に View ⾃⾝が更新するが、誰でも更新可能

Slide 29

Slide 29 text

Single source of truth 29 誰が View のイベントに反応する? 誰が状態を所有してる? 誰が状態を更新する? 状態の所有者がイベントに反応する。 状態の所有者は常に1つ。 状態の所有者のみが更新する。

Slide 30

Slide 30 text

Single source of truth in Compose 30 @Model class FormState(var optionChecked: Boolean = false) @Composable fun Form(formState: FormState = FormState()) { Checkbox( checked = formState.optionChecked, onCheckedChange = { newState -> formState.optionChecked = newState } ) } ※ CheckBox の⽂⾔は別途 Text で表⽰する必要がある

Slide 31

Slide 31 text

Data flows 🔄 31

Slide 32

Slide 32 text

データの流れは⼀⽅向 32 NewsContent NewsCard NewsCard NewsCard Image Text Image Text Image Text Business Logics User Data Events ■ = Composable

Slide 33

Slide 33 text

@Composable fun NewsContent(newsItems: List) { newsItems.forEach { newsItem -> NewsCard(newsItem) } } @Composable fun NewsCard(newsItem: NewsItem) { Column { SimpleImage( image = +imageResource(newsItem.imageId) ) Text(text = newsItem.title) } } データはトップダウンに伝搬 • 引数で渡す • 親 → ⼦ へ伝搬 • グローバル変数を参照しない 33

Slide 34

Slide 34 text

イベントはボトムアップに伝搬 ラムダ式を引数として 親 → ⼦ に渡す 34 NewsContent NewsCard NewsCard Image Text Image Text Business Logics User Events ■ = Composable { } { } { }

Slide 35

Slide 35 text

35 @Composable fun NewsContent( newsItems: List, newsState: NewsState = NewsState() // Model ) { Column { TopAppBar(title = { Text(text = newsState.selectedNewsTitle ?: "not selected") }) newsItems.forEach { newsItem -> NewsCard( newsItem = newsItem, onClick = { newsState.selectedNewsTitle = newsItem.title } ) } } } @Composable fun NewsCard(newsItem: NewsItem, onClick: () -> Unit) { Clickable(onClick = onClick) { // Image ͱ Text } } ※ スタイルは調整してあります

Slide 36

Slide 36 text

既存コードとの互換性 (未実装) 36

Slide 37

Slide 37 text

Composable → View 変換 (予定) 37 What's New in Jetpack Compose (Android Dev Summit ’19) のスライドより

Slide 38

Slide 38 text

Composable 内で View を使う 38 • ⾃作したコンポーネントや外部ライブラリとの共存させたい • ViewBinding ? • 既存の View をラップした Composable を⽤意する? • 既存の View は Single source of truth の設計ではない問題

Slide 39

Slide 39 text

🚀 Jetpack Compose ⚒ 39 1. Unbundle な UI ツールキットの提供 2. 宣⾔的な記述による UI 時系列の気配りからの解放 3. 簡潔な状態管理とイベントハンドリングの実現 4. Kotlin の⾔語機能をフルに使ったレイアウト ※ Technical Preview なのでプロダクトにはまだ使えない

Slide 40

Slide 40 text

Jetpack Compose の正体 🔍 40 UIツールライブラリ Composable 関数, Material Theme, etc Kotlin コンパイラプラグイン @Composable, @Model からのコード⽣成 +

Slide 41

Slide 41 text

その他 • Layout • Effects & memo • Theme • 気になる⼈は Codelab を⾒てね!
 https://codelabs.developers.google.com/codelabs/jetpack-compose-basics/#0 41