9
3

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 3 years have passed since last update.

Understanding Composeメモ

Last updated at Posted at 2019-10-27

概要

Hello Worldだけ見て以下のような記事を書いていたのですが、ちゃんとYouTubeを見るべきだったので見ました。
https://qiita.com/takahirom/items/ed9fbf3788b142aad904

Understanding Compose (Android Dev Summit '19)
https://www.youtube.com/watch?v=Q9MtlmmN4Q0

Inheritance vs Composition

Composeの重要な概念としてCompositionがある。

例1

例えば、入力フォームがあって、日付の範囲を指定したい場合に、2つTextInputを持ちたい場合どうするのか?

Inheritanceだと2つDateを受け取りたいが1つしか継承できない

class Input: View{}
class ValidatedInput: Input(){}
class DateInput: ValidatedInput() {}
class DateRangeInput: ???? // ← **

ComposeのComposition Modelだと単に2回呼ぶだけで解決する

@Composable
fun DateInput(value: Date, onChange: (Date) -> Unit) {
    ValidatedInput(
        value = value,
        onChange = onChange,
        isValid = value.after(Date())
    )
}
@Composable
fun DateRangeInput(value: DateRange, onChange: (DateRange) -> Unit){
    DateInput(value = value.start, onChange = ...)
    DateInput(value = value.end, onChange = ...)
}

例2

例えば2つの属性を持つ要素を作りたい場合はどうすればよいか?

Inheritanceだと1つしか継承できないので、同様の問題が起こる。

class FancyBox: View(){...}
class EditForm : FormView(){...}
class FancyEditForm : ???

ComposeのComposition Modelだと以下のようにclidrenの中で呼んであげるようにするだけで解決できる。

@Composable fun FancyBox(clidren: @Composable ()-> Unit) {
  Box(fancy) { clidren() }
}
@Composable fun FancyEditForm(...) {
  FancyBox { EditForm(...) }
}

Recompositon

Composeのヒエラルキーの一部が変わったときにすべてが変わる必要がない。
LiveDataを使っている場合の例は以下のようにobserveできる。

fun Messages(liveMsgs: LiveData<MessageData>) {
  val msgs = +observe(liveMsgs)
  for (msg in msgs) {
    Message(msg)
  }
}

もっとかんたんな例

  @Composable
  fun Counter() {
    val count = +state { 0 }
    Button(
      text="Count: ${count.value} "
      onPress={ count.value += 1 }
    )
  }

+stateで以下のようなクラスのインスタンスが作られる

@Model
class State<T> {
  val value: T
}

@Modelはそのクラスのプロパティが書き込みと読み込みがobservableであることを示す。
Composeは自動的にsubscribeして更新してくれる。

How does compose work?

suspend functionと@Composeのメソッドは似ていて、@Composeがついているメソッドはついていないメソッドから呼び出すことができない。

fun Example(a: ()-> Unit, b: @Composable ()-> Unit) {
  a()// allowed
  b()// not allowed
}

Composeは"Gap buffer"と呼ばれるデータ構造を使っている。これはテキストエディタで利用されているものと同じです

Slotテーブルで管理していて、if文で状態が変わる場合どのようになるか?

@Composable fun App() {
  val result = getData()
  if (result == null) {
    Loading(...)
  } else {
    Header(..)
    Body(result)
  }
}

コンパイル時はこのようにSlotテーブルに入れるための文が入ります。

@Composable fun App() {
  val result = getData()
  if (result == null) {
    $composer.start(123)
    Loading(...)
    $composer.end()
  } else {
    $composer.start(456)
    Header(..)
    Body(result)
    $composer.end()
  }
}

最初に実行するときにgetData()がnullだった場合このようにSlotTableに値が入ります。
image.png

2回目にgetData()がnullじゃなかった場合に面白いことが起こり、テーブル内のデータを少し消してやり直します。
image.png

このコンセプトを"Positional Memoization"と呼ぶ。

データの変更をキャッシュしている。
コンパイル時に変更されるデータのみ監視するように変更している。

recomposeは以下のように実行される。
image.png

9
3
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
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?