Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

product 4

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

࣮ࡍʹ࢖ͬͯΈΑ͏ 15

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

ComponentΛॻ͍ͯΈͨ 19

Slide 20

Slide 20 text

ίʔυͷઆ໌ 20

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

StethoͰ͍ͬͯ͡ΈΑ͏ 43

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

͓ΘΓ 51

Slide 52

Slide 52 text

Notes 

Slide 53

Slide 53 text

༨ஊɿ຤ඌͷ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

Slide 54

Slide 54 text

੡࡞ऀʹΑΔ঺հϒϩά • 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

Slide 55

Slide 55 text

ϒϩάͳͲ • 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

Slide 56

Slide 56 text

ͦͷଞ • 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