Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Lithoを使ってみた

 Lithoを使ってみた

2017/05/09 shibuya.apk #14

ymnder

May 09, 2017
Tweet

More Decks by ymnder

Other Decks in Programming

Transcript

  1. LithoΛ࢖ͬͯΈͨ
    2017/05/09 shibuya.apk #14

    View Slide

  2. sample App
    https://github.com/ymnder/BLite
    2

    View Slide

  3. whoami
    • Ryo Yamazaki / Nikkei Application Engineer
    • twitter:@ymnd
    • github:@ymnder
    • google i/o ߦ͖·͢
    3

    View Slide

  4. product
    4

    View Slide

  5. ࠓ೔ͷ͓඼ॻ͖
    ᶃLithoͱ͸
    ᶄLithoͰॻ͍ͯΈͨ
    ᶅ࢖ͬͯΈͯͲ͏͔ͩͬͨ
    5

    View Slide

  6. Lithoͱ͸
    • facebook੡ͷUI framework ʢv0.2.0ʣminSDK 15
    • ReactͱComponentKitʹΠϯεύΠΞ͞Ε͍ͯΔ
    • RecyclerViewʹج͍ͮͨෳࡶ͔ͭεΫϩʔϥϒϧͳUI
    Λ࣮૷͢ΔͨΊʹͭ͘ΒΕͨ
    6

    View Slide

  7. Lithoͷڧ͍ͱ͜Ζ
    • RecyclerView
    • 1000ms / 60fps ≒ 16ms
    • όΠϯυɾଌఆɾϨΠΞ΢τ·ͰΛߦ͏ඞཁ
    • FacebookͷNewsFeedͷΑ͏ͳͨ͘͞ΜͷViewType͕
    ૝ఆ͞ΕΔ৔߹ʹޮՌΛൃش͢Δ
    7

    View Slide

  8. LithoͷΞʔΩςΫνϟ
    ᶃDeclarative
    ᶄAsynchronous layout
    ᶅFlatter view hierarchies
    ᶆFine-grained recycling
    8

    View Slide

  9. ᶃDeclarative: એݴܕ
    • UIίϯϙʔωϯτΛఆٛ͢ΔએݴܕAPIΛ࢖༻͢Δ
    • immutableͳೖྗʹج͖ͮUIͷϨΠΞ΢τΛهड़͢Δ
    • code genarationͰίʔυΛγϯϓϧ͔ͭ؆୯ʹอͯΔ
    9

    View Slide

  10. ᶄAsynchronous layout: ඇಉظϨΠΞ΢τ
    • UIεϨουΛϒϩοΫͤͣʹࣄલʹUIΛଌఆ͠ϨΠΞ
    ΢τͰ͖Δ
    10

    View Slide

  11. ᶅFlatter view hierarchies: ϑϥοτͳViewHierarchy
    • ϨΠΞ΢τʹYogaΛ࢖༻͠ɺࣗಈతʹUIؚ͕Ή
    ViewGroupsΛݮΒ͢
    11

    View Slide

  12. ᶅFlatter view hierarchies: ϑϥοτͳViewHierarchy
    • දࣔཁૉ͕ҰຕͷϑϥοτͳଘࡏʹͳΔ
    • ࣮ߦ࣌ʹ͸View͸LithoViewԼͷComponentHostʹू
    ໿͞ΕΔ
    12

    View Slide

  13. ConstraintLayoutͱͷࠩҟ
    • ྆ํͱ΋Viewͷ֊૚Λϑϥοτʹͯ͘͠ΕΔ
    • Litho͸FlexboxΛ࣮ݱ͢ΔYogaΛ࢖༻͢Δ
    • xmlͰͳ࣮͘૷ͯ͠૊Ή
    • දࣔ࣌ʹTextViewͳͲͷཁૉΛશ෦̍ຕʹ·ͱΊΔ
    13

    View Slide

  14. ᶆFine-grained recycling: ͖Ίࡉ͔͍ϦαΠΫϧ
    • ֤ςΩετɾը૾ɾө૾ͷΑ͏ͳUIΞΠςϜ͸ݸผʹϦ
    αΠΫϧ͞ΕΔ
    • RecyclerViewͱҟͳΓɺListItem୯ҐͰ࠶ར༻͞Εͣɺ
    ListItemͷதͷཁૉ୯ҐͰ࠶࢖༻͞ΕΔ
    14

    View Slide

  15. ࣮ࡍʹ࢖ͬͯΈΑ͏
    15

    View Slide

  16. LithoͰॻ͍ͯΈͨ
    dependencies {
    //Litho
    compile 'com.facebook.litho:litho-core:0.2.0'
    //contains basic component
    compile 'com.facebook.litho:litho-widget:0.2.0'
    //annotation processor
    compile 'com.facebook.litho:litho-annotations:0.2.0'
    annotationProcessor 'com.facebook.litho:litho-processor:0.2.0'
    //for Yoga. Yoga has dependencies for native
    compile 'com.facebook.soloader:soloader:0.2.0'
    //Stetho plugin
    debugCompile 'com.facebook.litho:litho-stetho:0.2.0'
    }
    16

    View Slide

  17. LithoͰॻ͍ͯΈͨ
    public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //ContextͷαϒΫϥεͰϥΠϒϥϦ಺Ͱ࢖͏৘ใΛ؅ཧ͢Δ
    final ComponentContext c = new ComponentContext(this);
    setContentView(
    //ComponentΛmountͨ͠ViewGroupΛฦ͢
    LithoView.create(
    this,
    SplashComponent.create(c).build()));
    }
    }
    17

    View Slide

  18. ComponentΛॻ͍ͯΈͨ
    //ଞͷίϯϙʔωϯτΛ·ͱΊΔίϯϙʔωϯτ
    @LayoutSpec
    public class SplashComponentSpec {
    @OnCreateLayout
    static ComponentLayout onCreateLayout(ComponentContext c) {
    return Column.create(c)
    .child(
    Text.create(c)
    .text(“Hello Litho :)”)
    .textSizeSp(30f)
    .withLayout()
    .alignSelf(YogaAlign.CENTER)
    ).justifyContent(YogaJustify.CENTER)
    .build();
    }
    }
    18

    View Slide

  19. ComponentΛॻ͍ͯΈͨ
    19

    View Slide

  20. ίʔυͷઆ໌
    20

    View Slide

  21. LithoͰॻ͍ͯΈͨ
    public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //ContextͷαϒΫϥεͰϥΠϒϥϦ಺Ͱ࢖͏৘ใΛ؅ཧ͢Δ
    final ComponentContext c = new ComponentContext(this);
    setContentView(
    //ComponentΛmountͨ͠ViewGroupΛฦ͢
    LithoView.create(
    this,
    SplashComponent.create(c).build()));
    }
    }
    21

    View Slide

  22. LithoͰॻ͍ͯΈͨ
    public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //ContextͷαϒΫϥεͰϥΠϒϥϦ಺Ͱ࢖͏৘ใΛ؅ཧ͢Δ
    final ComponentContext c = new ComponentContext(this);
    setContentView(
    //ComponentΛmountͨ͠ViewGroupΛฦ͢
    LithoView.create(
    this,
    SplashComponent.create(c).build()));
    }
    }
    22

    View Slide

  23. LithoͰॻ͍ͯΈͨ
    public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //ContextͷαϒΫϥεͰϥΠϒϥϦ಺Ͱ࢖͏৘ใΛ؅ཧ͢Δ
    final ComponentContext c = new ComponentContext(this);
    setContentView(
    //ComponentΛmountͨ͠ViewGroupΛฦ͢
    LithoView.create(
    this,
    SplashComponent.create(c).build()));
    }
    }
    23

    View Slide

  24. ComponentΛॻ͍ͯΈͨ
    //ଞͷίϯϙʔωϯτΛ·ͱΊΔίϯϙʔωϯτ
    @LayoutSpec
    public class SplashComponentSpec {
    @OnCreateLayout
    static ComponentLayout onCreateLayout(ComponentContext c) {
    return Column.create(c)
    .child(
    Text.create(c)
    .text(“Hello Litho :)”)
    .textSizeSp(30f)
    .withLayout()
    .alignSelf(YogaAlign.CENTER)
    ).justifyContent(YogaJustify.CENTER)
    .build();
    }
    }
    24

    View Slide

  25. ComponentΛॻ͍ͯΈͨ
    //ଞͷίϯϙʔωϯτΛ·ͱΊΔίϯϙʔωϯτ
    @LayoutSpec
    public class SplashComponentSpec {
    @OnCreateLayout
    static ComponentLayout onCreateLayout(ComponentContext c) {
    return Column.create(c)
    .child(
    Text.create(c)
    .text(“Hello Litho :)”)
    .textSizeSp(30f)
    .withLayout()
    .alignSelf(YogaAlign.CENTER)
    ).justifyContent(YogaJustify.CENTER)
    .build();
    }
    }
    25

    View Slide

  26. ComponentͷΞϊςʔγϣϯ
    • LayoutSpecʢྫɿListItemʣ
    • ଞͷίϯϙʔωϯτΛಛఆͷϨΠΞ΢τʹ·ͱΊΔɻ
    ViewGroupతͳଘࡏ
    • MountSpecʢྫɿRecyclerʣ
    • View΍DrawableΛϨϯμϦϯά͢ΔɻϨΠΞ΢τͷ
    ܭࢉॲཧ͕ఆٛ͞ΕΔ
    26

    View Slide

  27. ComponentΛॻ͍ͯΈͨ
    //ଞͷίϯϙʔωϯτΛ·ͱΊΔίϯϙʔωϯτ
    @LayoutSpec
    public class SplashComponentSpec {
    @OnCreateLayout
    static ComponentLayout onCreateLayout(ComponentContext c) {
    return Column.create(c)
    .child(
    Text.create(c)
    .text(“Hello Litho :)”)
    .textSizeSp(30f)
    .withLayout()
    .alignSelf(YogaAlign.CENTER)
    ).justifyContent(YogaJustify.CENTER)
    .build();
    }
    }
    27

    View Slide

  28. ComponentΛॻ͍ͯΈͨ
    //ଞͷίϯϙʔωϯτΛ·ͱΊΔίϯϙʔωϯτ
    @LayoutSpec
    public class SplashComponentSpec {
    @OnCreateLayout
    static ComponentLayout onCreateLayout(ComponentContext c) {
    return Column.create(c)
    .child(
    Text.create(c)
    .text(“Hello Litho :)”)
    .textSizeSp(30f)
    .withLayout()
    .alignSelf(YogaAlign.CENTER)
    ).justifyContent(YogaJustify.CENTER)
    .build();
    }
    }
    28

    View Slide

  29. Layout
    • ֤ཁૉΛͲͷํ޲ʹ഑ஔ͢Δ͔ܾΊΔίϯςφ
    • ೖΕࢠʹͯ͠ෳࡶͳ഑ஔΛߦ͏͜ͱ΋ՄೳͰ͋Δ
    //linear layout: horizontal
    Row.create(c)
    .child(…)
    .build();
    //linear layout: vertical
    Column.create(c)
    .child(…)
    .build();
    29

    View Slide

  30. ComponentΛॻ͍ͯΈͨ
    //ଞͷίϯϙʔωϯτΛ·ͱΊΔίϯϙʔωϯτ
    @LayoutSpec
    public class SplashComponentSpec {
    @OnCreateLayout
    static ComponentLayout onCreateLayout(ComponentContext c) {
    return Column.create(c)
    .child(
    Text.create(c)
    .text(“Hello Litho :)”)
    .textSizeSp(30f)
    .withLayout()
    .alignSelf(YogaAlign.CENTER)
    ).justifyContent(YogaJustify.CENTER)
    .build();
    }
    }
    30

    View Slide

  31. ComponentΛॻ͍ͯΈͨ
    //ଞͷίϯϙʔωϯτΛ·ͱΊΔίϯϙʔωϯτ
    @LayoutSpec
    public class SplashComponentSpec {
    @OnCreateLayout
    static ComponentLayout onCreateLayout(ComponentContext c) {
    return Column.create(c)
    .child(
    Text.create(c)
    .text(“Hello Litho :)”)
    .textSizeSp(30f)
    .withLayout()
    .alignSelf(YogaAlign.CENTER)
    ).justifyContent(YogaJustify.CENTER)
    .build();
    }
    }
    31

    View Slide

  32. Component
    • ࠷ॳ͔Β༻ҙ͞Ε͍ͯΔجຊతͳView
    //like TextView
    Text.create(c);
    //like ImageView
    Image.create(c);
    32

    View Slide

  33. Recycler
    @OnCreateLayout
    static ComponentLayout onCreateLayout(final ComponentContext c) {
    final RecyclerBinder recyclerBinder = new RecyclerBinder(c,
    new LinearLayoutInfo(c, VERTICAL, false));
    final RecyclerEventsController controller = new RecyclerEventsController();
    //...
    return Recycler.create(c)
    .binder(recyclerBinder)
    .recyclerEventsController(controller)
    .refreshHandler(ListComponent.onPTRrefresh(c, recyclerBinder, controller))
    .onScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);
    //...
    }
    })
    .build();
    }
    33

    View Slide

  34. Recycler
    @OnCreateLayout
    static ComponentLayout onCreateLayout(final ComponentContext c) {
    final RecyclerBinder recyclerBinder = new RecyclerBinder(c,
    new LinearLayoutInfo(c, VERTICAL, false));
    final RecyclerEventsController controller = new RecyclerEventsController();
    //...
    return Recycler.create(c)
    .binder(recyclerBinder)
    .recyclerEventsController(controller)
    .refreshHandler(ListComponent.onPTRrefresh(c, recyclerBinder, controller))
    .onScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);
    //...
    }
    })
    .build();
    }
    34

    View Slide

  35. Recycler
    • dataͱviewΛbind͢ΔଘࡏɻAdpaterͱLayoutManagerͷػೳΛ࣋ͭ
    • ୈೋҾ਺ʹLayoutManagerΛwrap͢ΔLayoutInfoΛͱΔɻ
    • LinearLayoutInfoͷ৔߹͸ɺLinearLayoutManagerΛ಺෦తʹ͍࣋ͬͯΔ
    • GridLayoutInfo΋༻ҙ͞Ε͍ͯΔ
    final RecyclerBinder recyclerBinder = new RecyclerBinder(c,
    new LinearLayoutInfo(c, VERTICAL, false));
    35

    View Slide

  36. Recycler
    @OnCreateLayout
    static ComponentLayout onCreateLayout(final ComponentContext c) {
    final RecyclerBinder recyclerBinder = new RecyclerBinder(c,
    new LinearLayoutInfo(c, VERTICAL, false));
    final RecyclerEventsController controller = new RecyclerEventsController();
    //...
    return Recycler.create(c)
    .binder(recyclerBinder)
    .recyclerEventsController(controller)
    .refreshHandler(ListComponent.onPTRrefresh(c, recyclerBinder, controller))
    .onScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);
    //...
    }
    })
    .build();
    }
    36

    View Slide

  37. Recycler
    @OnCreateLayout
    static ComponentLayout onCreateLayout(final ComponentContext c) {
    final RecyclerBinder recyclerBinder = new RecyclerBinder(c,
    new LinearLayoutInfo(c, VERTICAL, false));
    final RecyclerEventsController controller = new RecyclerEventsController();
    //...
    return Recycler.create(c)
    .binder(recyclerBinder)
    .recyclerEventsController(controller)
    .refreshHandler(ListComponent.onPTRrefresh(c, recyclerBinder, controller))
    .onScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);
    //...
    }
    })
    .build();
    }
    37

    View Slide

  38. Recycler
    • Recycler͸RecyclerViewΛ಺෦తʹ࣋ͭRecyclerViewWrapperΛ༗͢Δ
    • RecyclerViewWrapper͸SwipeRefreshLayoutΛܧঝ͍ͯ͠Δ
    • ͜ΕΛίϯτϩʔϧ͢Δ͢ΔͨΊʹcontrollerΛ࡞੒͍ͯ͠Δ
    final RecyclerEventsController controller = new RecyclerEventsController();
    38

    View Slide

  39. Recycler
    @OnCreateLayout
    static ComponentLayout onCreateLayout(final ComponentContext c) {
    final RecyclerBinder recyclerBinder = new RecyclerBinder(c,
    new LinearLayoutInfo(c, VERTICAL, false));
    final RecyclerEventsController controller = new RecyclerEventsController();
    //...
    return Recycler.create(c)
    .binder(recyclerBinder)
    .recyclerEventsController(controller)
    .refreshHandler(ListComponent.onPTRrefresh(c, recyclerBinder, controller))
    .onScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);
    //...
    }
    })
    .build();
    }
    39

    View Slide

  40. Recycler
    @OnCreateLayout
    static ComponentLayout onCreateLayout(final ComponentContext c) {
    final RecyclerBinder recyclerBinder = new RecyclerBinder(c,
    new LinearLayoutInfo(c, VERTICAL, false));
    final RecyclerEventsController controller = new RecyclerEventsController();
    //...
    return Recycler.create(c)
    .binder(recyclerBinder)
    .recyclerEventsController(controller)
    .refreshHandler(ListComponent.onPTRrefresh(c, recyclerBinder, controller))
    .onScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);
    //...
    }
    })
    .build();
    }
    40

    View Slide

  41. Event
    • EventΛड͚औΓ͍ͨComponentʹఆٛ͢Δ
    @OnEvent(PTRRefreshEvent.class)
    static void onPTRrefresh(final ComponentContext c,
    @Param final RecyclerBinder recyclerBinder,
    @Param final RecyclerEventsController controller){
    //…
    controller.clearRefreshing();
    }
    41

    View Slide

  42. Stetho plugin
    • Stetho(v1.5.0)ͱ࿈ܞ
    • re-start / re-compileͤͣʹमਖ਼Ͱ͖Δ
    • ࣮ࡍʹඍमਖ਼ΛՃ͑ͳ͕Βಈ͖Λ͔֬ΊΒΕΔ
    • Yogaͱ΋༑ୡʹͳΕͦ͏
    • AndroidStudioͷlayout inspectorͰ͸ϑϥοτͳView
    ʹͳ͍ͬͯΔ
    42

    View Slide

  43. StethoͰ͍ͬͯ͡ΈΑ͏
    43

    View Slide

  44. debug options
    • ComponentsConfigurationͷ஋Λtrueʹ͢Δͱλον
    ΤϦΞͱViewͷڥքΛͦΕͧΕՄࢹԽͰ͖Δ
    44

    View Slide

  45. debug options
    ᶃdebugHighlightInteractiveBounds
    λονΤϦΞΛՄࢹԽ
    45

    View Slide

  46. debug options
    ᶄdebugHighlightMountBounds
    ViewͷڥքΛՄࢹԽ
    46

    View Slide

  47. ࢖ͬͯΈͯͲ͏͔ͩͬͨ
    • xmlͰͳ͍ܗͰViewΛ૊Ήͷ͕৽઱ͩͬͨ
    • YogaʹΑΓࣗಈతʹྑ͍Ґஔʹௐ੔͞ΕΔͷָ͕
    47

    View Slide

  48. ࢖ͬͯΈͯͲ͏͔ͩͬͨ
    • ίʔυΛ௥͍ʹ͍͘
    • ࣗಈੜ੒ޙͷΫϥεΛࢀর͢ΔͨΊɺfind usage͕΍Γʹ͍͘
    • annotation processorނʹίϯύΠϧϑΣʔζʹ࣮ߦ͞ΕΔ
    • SpecʹΞϊςʔγϣϯΛ௥Ճͨ͠৔߹࠶Ϗϧυ͕ඞཁͰ͋Δ
    • δΣενϟʔ΍ΞχϝʔγϣϯΛ൐͏μΠφϛοΫͳUI͸ࠓͷͱ
    ͜Ζͳ͍
    • ࠓޙ௥Ճ͞ΕΔΒ͍͠
    • xmlͰͷैདྷͷϨΠΞ΢τΛ͢΂ͯ୅ସ͢Δ΋ͷͰ͸ͳ͍
    • AndroidStudioͰPreview͢Δ͜ͱ͕Ͱ͖ͳ͍
    48

    View Slide

  49. ࢖ͬͯΈͯͲ͏͔ͩͬͨ
    • ෳࡶͳViewHolderͷ૊Έ߹Θ͕ͤͳ͍ݶΓ͸ෆཁʁ
    49

    View Slide

  50. ΋ͬͱௐ͍ࠪͨ͠ͱ͜Ζ
    • Asynchronous Layout
    • Immutability and thread safety
    • http://fblitho.com/docs/asynchronous-layout
    • UIεϨουʹ౉͢લʹlayoutͱmeasureΛߦ͍ͬͯΔ
    • ͲͷΑ͏ʹόοΫάϥ΢ϯυͰॲཧ͞ΕͯΔͷ͔ʁ
    50

    View Slide

  51. ͓ΘΓ
    51

    View Slide

  52. Notes

    View Slide

  53. ༨ஊɿ຤ඌͷSpecͱ͸
    • ྫɿNameComponentSpec
    • ίϯϙʔωϯτͷ໊લ͸SpecͰऴΘΒͤΔ
    • annotation processorͰNameComponentʹͳΔ
    • javapoet࢖༻͍ͯ͠Δɻ຤ඌʹSpecΛ͚ͭΔɻ
    • ɾhttps://github.com/facebook/litho/blob/master/
    litho-processor/src/main/java/com/facebook/litho/
    specmodels/model/SpecModelValidation.java#L53
    53

    View Slide

  54. ੡࡞ऀʹΑΔ঺հϒϩά
    • Lithoʹ͍ͭͯ෼͔Γ΍͘͢঺հ͞Ε͍ͯΔ
    • https://code.facebook.com/posts/
    1187475984695956/open-sourcing-litho-a-
    declarative-ui-framework-for-android/
    • LithoͷίϯηϓτɿComponents for Android
    • https://code.facebook.com/posts/
    531104390396423/components-for-android-a-
    declarative-framework-for-efficient-uis
    54

    View Slide

  55. ϒϩάͳͲ
    • CustomButtonΛͭͬͯ͘Έͨ
    • https://medium.com/@p.tournaris/litho-how-to-create-a-custom-
    button-b460b5a3b828
    • LithoͷReview
    • https://medium.com/proandroiddev/facebook-litho-review-
    b591372d85be
    • DroidCon London 2016
    • https://skillsmatter.com/skillscasts/8418-flat-as-a-pancake#video
    55

    View Slide

  56. ͦͷଞ
    • https://news.ycombinator.com/item?id=14142321
    • https://www.reddit.com/r/androiddev/comments/
    68i0hg/
    review_of_the_new_facebook_litho_framework_part_1/
    • https://www.reddit.com/r/androiddev/comments/
    66g0ve/facebook_for_developers_litho_a_declarative/
    • https://www.reddit.com/r/androiddev/comments/
    6659bn/litho_a_declarative_ui_framework_for_android/
    • https://www.reddit.com/r/androiddev/comments/
    6784bv/glide_imageloading_component_for_litho/
    56

    View Slide