Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Lithoを使ってみた
Search
ymnder
May 09, 2017
Programming
2
1k
Lithoを使ってみた
2017/05/09 shibuya.apk #14
ymnder
May 09, 2017
Tweet
Share
More Decks by ymnder
See All by ymnder
What’s new in Google Play's billing system
ymnder
1
190
Deep Linksをはじめよう
ymnder
0
330
Introduction to Wear OS Application Development
ymnder
0
460
CircleCIを使ったAndroidの開発フローの効率化とtips
ymnder
1
1.2k
Introduction to new features of Google Play Billing
ymnder
2
280
運用から学ぶPlay Billing Library
ymnder
2
720
What’s new in Google Play Billing v1.2
ymnder
0
680
詳解定期購入
ymnder
7
6k
社内向けライブラリを設計・運用する話
ymnder
0
950
Other Decks in Programming
See All in Programming
エンジニアとして関わる要件と仕様(公開用)
murabayashi
0
280
ECS Service Connectのこれまでのアップデートと今後のRoadmapを見てみる
tkikuc
2
250
Jakarta EE meets AI
ivargrimstad
0
600
RubyLSPのマルチバイト文字対応
notfounds
0
120
Macとオーディオ再生 2024/11/02
yusukeito
0
370
Ethereum_.pdf
nekomatu
0
460
CSC509 Lecture 12
javiergs
PRO
0
160
Jakarta EE meets AI
ivargrimstad
0
530
Hotwire or React? ~アフタートーク・本編に含めなかった話~ / Hotwire or React? after talk
harunatsujita
1
120
聞き手から登壇者へ: RubyKaigi2024 LTでの初挑戦が 教えてくれた、可能性の星
mikik0
1
130
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
1
100
Make Impossible States Impossibleを 意識してReactのPropsを設計しよう
ikumatadokoro
0
170
Featured
See All Featured
Bash Introduction
62gerente
608
210k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
26
2.1k
Build The Right Thing And Hit Your Dates
maggiecrowley
33
2.4k
Measuring & Analyzing Core Web Vitals
bluesmoon
4
120
The World Runs on Bad Software
bkeepers
PRO
65
11k
Keith and Marios Guide to Fast Websites
keithpitt
409
22k
The Language of Interfaces
destraynor
154
24k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
109
49k
Reflections from 52 weeks, 52 projects
jeffersonlam
346
20k
Building Applications with DynamoDB
mza
90
6.1k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
720
Documentation Writing (for coders)
carmenintech
65
4.4k
Transcript
LithoΛͬͯΈͨ 2017/05/09 shibuya.apk #14
sample App https://github.com/ymnder/BLite 2
whoami • Ryo Yamazaki / Nikkei Application Engineer • twitter:@ymnd
• github:@ymnder • google i/o ߦ͖·͢ 3
product 4
ࠓͷ͓ॻ͖ ᶃLithoͱ ᶄLithoͰॻ͍ͯΈͨ ᶅͬͯΈͯͲ͏͔ͩͬͨ 5
Lithoͱ • facebookͷUI framework ʢv0.2.0ʣminSDK 15 • ReactͱComponentKitʹΠϯεύΠΞ͞Ε͍ͯΔ • RecyclerViewʹج͍ͮͨෳࡶ͔ͭεΫϩʔϥϒϧͳUI
Λ࣮͢ΔͨΊʹͭ͘ΒΕͨ 6
Lithoͷڧ͍ͱ͜Ζ • RecyclerView • 1000ms / 60fps ≒ 16ms •
όΠϯυɾଌఆɾϨΠΞτ·ͰΛߦ͏ඞཁ • FacebookͷNewsFeedͷΑ͏ͳͨ͘͞ΜͷViewType͕ ఆ͞ΕΔ߹ʹޮՌΛൃش͢Δ 7
LithoͷΞʔΩςΫνϟ ᶃDeclarative ᶄAsynchronous layout ᶅFlatter view hierarchies ᶆFine-grained recycling 8
ᶃDeclarative: એݴܕ • UIίϯϙʔωϯτΛఆٛ͢ΔએݴܕAPIΛ༻͢Δ • immutableͳೖྗʹج͖ͮUIͷϨΠΞτΛهड़͢Δ • code genarationͰίʔυΛγϯϓϧ͔ͭ؆୯ʹอͯΔ 9
ᶄAsynchronous layout: ඇಉظϨΠΞτ • UIεϨουΛϒϩοΫͤͣʹࣄલʹUIΛଌఆ͠ϨΠΞ τͰ͖Δ 10
ᶅFlatter view hierarchies: ϑϥοτͳViewHierarchy • ϨΠΞτʹYogaΛ༻͠ɺࣗಈతʹUIؚ͕Ή ViewGroupsΛݮΒ͢ 11
ᶅFlatter view hierarchies: ϑϥοτͳViewHierarchy • දࣔཁૉ͕ҰຕͷϑϥοτͳଘࡏʹͳΔ • ࣮ߦ࣌ʹViewLithoViewԼͷComponentHostʹू ͞ΕΔ 12
ConstraintLayoutͱͷࠩҟ • ྆ํͱViewͷ֊Λϑϥοτʹͯ͘͠ΕΔ • LithoFlexboxΛ࣮ݱ͢ΔYogaΛ༻͢Δ • xmlͰͳ࣮ͯ͘͠Ή • දࣔ࣌ʹTextViewͳͲͷཁૉΛશ෦̍ຕʹ·ͱΊΔ 13
ᶆFine-grained recycling: ͖Ίࡉ͔͍ϦαΠΫϧ • ֤ςΩετɾը૾ɾө૾ͷΑ͏ͳUIΞΠςϜݸผʹϦ αΠΫϧ͞ΕΔ • RecyclerViewͱҟͳΓɺListItem୯ҐͰ࠶ར༻͞Εͣɺ ListItemͷதͷཁૉ୯ҐͰ࠶༻͞ΕΔ 14
࣮ࡍʹͬͯΈΑ͏ 15
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
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
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
ComponentΛॻ͍ͯΈͨ 19
ίʔυͷઆ໌ 20
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
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
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
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
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
ComponentͷΞϊςʔγϣϯ • LayoutSpecʢྫɿListItemʣ • ଞͷίϯϙʔωϯτΛಛఆͷϨΠΞτʹ·ͱΊΔɻ ViewGroupతͳଘࡏ • MountSpecʢྫɿRecyclerʣ • ViewDrawableΛϨϯμϦϯά͢ΔɻϨΠΞτͷ
ܭࢉॲཧ͕ఆٛ͞ΕΔ 26
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
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
Layout • ֤ཁૉΛͲͷํʹஔ͢Δ͔ܾΊΔίϯςφ • ೖΕࢠʹͯ͠ෳࡶͳஔΛߦ͏͜ͱՄೳͰ͋Δ //linear layout: horizontal Row.create(c) .child(…)
.build(); //linear layout: vertical Column.create(c) .child(…) .build(); 29
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
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
Component • ࠷ॳ͔Β༻ҙ͞Ε͍ͯΔجຊతͳView //like TextView Text.create(c); //like ImageView Image.create(c); 32
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
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
Recycler • dataͱviewΛbind͢ΔଘࡏɻAdpaterͱLayoutManagerͷػೳΛ࣋ͭ • ୈೋҾʹLayoutManagerΛwrap͢ΔLayoutInfoΛͱΔɻ • LinearLayoutInfoͷ߹ɺLinearLayoutManagerΛ෦తʹ͍࣋ͬͯΔ • GridLayoutInfo༻ҙ͞Ε͍ͯΔ final
RecyclerBinder recyclerBinder = new RecyclerBinder(c, new LinearLayoutInfo(c, VERTICAL, false)); 35
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
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
Recycler • RecyclerRecyclerViewΛ෦తʹ࣋ͭRecyclerViewWrapperΛ༗͢Δ • RecyclerViewWrapperSwipeRefreshLayoutΛܧঝ͍ͯ͠Δ • ͜ΕΛίϯτϩʔϧ͢Δ͢ΔͨΊʹcontrollerΛ࡞͍ͯ͠Δ final RecyclerEventsController controller
= new RecyclerEventsController(); 38
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
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
Event • EventΛड͚औΓ͍ͨComponentʹఆٛ͢Δ @OnEvent(PTRRefreshEvent.class) static void onPTRrefresh(final ComponentContext c, @Param
final RecyclerBinder recyclerBinder, @Param final RecyclerEventsController controller){ //… controller.clearRefreshing(); } 41
Stetho plugin • Stetho(v1.5.0)ͱ࿈ܞ • re-start / re-compileͤͣʹमਖ਼Ͱ͖Δ • ࣮ࡍʹඍमਖ਼ΛՃ͑ͳ͕Βಈ͖Λ͔֬ΊΒΕΔ
• Yogaͱ༑ୡʹͳΕͦ͏ • AndroidStudioͷlayout inspectorͰϑϥοτͳView ʹͳ͍ͬͯΔ 42
StethoͰ͍ͬͯ͡ΈΑ͏ 43
debug options • ComponentsConfigurationͷΛtrueʹ͢Δͱλον ΤϦΞͱViewͷڥքΛͦΕͧΕՄࢹԽͰ͖Δ 44
debug options ᶃdebugHighlightInteractiveBounds λονΤϦΞΛՄࢹԽ 45
debug options ᶄdebugHighlightMountBounds ViewͷڥքΛՄࢹԽ 46
ͬͯΈͯͲ͏͔ͩͬͨ • xmlͰͳ͍ܗͰViewΛΉͷ͕৽ͩͬͨ • YogaʹΑΓࣗಈతʹྑ͍Ґஔʹௐ͞ΕΔͷָ͕ 47
ͬͯΈͯͲ͏͔ͩͬͨ • ίʔυΛ͍ʹ͍͘ • ࣗಈੜޙͷΫϥεΛࢀর͢ΔͨΊɺfind usage͕Γʹ͍͘ • annotation processorނʹίϯύΠϧϑΣʔζʹ࣮ߦ͞ΕΔ •
SpecʹΞϊςʔγϣϯΛՃͨ͠߹࠶Ϗϧυ͕ඞཁͰ͋Δ • δΣενϟʔΞχϝʔγϣϯΛ͏μΠφϛοΫͳUIࠓͷͱ ͜Ζͳ͍ • ࠓޙՃ͞ΕΔΒ͍͠ • xmlͰͷैདྷͷϨΠΞτΛͯ͢ସ͢ΔͷͰͳ͍ • AndroidStudioͰPreview͢Δ͜ͱ͕Ͱ͖ͳ͍ 48
ͬͯΈͯͲ͏͔ͩͬͨ • ෳࡶͳViewHolderͷΈ߹Θ͕ͤͳ͍ݶΓෆཁʁ 49
ͬͱௐ͍ࠪͨ͠ͱ͜Ζ • Asynchronous Layout • Immutability and thread safety •
http://fblitho.com/docs/asynchronous-layout • UIεϨουʹ͢લʹlayoutͱmeasureΛߦ͍ͬͯΔ • ͲͷΑ͏ʹόοΫάϥϯυͰॲཧ͞ΕͯΔͷ͔ʁ 50
͓ΘΓ 51
Notes
༨ஊɿඌͷ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
࡞ऀʹΑΔհϒϩά • 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
ϒϩάͳͲ • 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
ͦͷଞ • 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