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
1.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
360
Deep Linksをはじめよう
ymnder
0
420
Introduction to Wear OS Application Development
ymnder
0
530
CircleCIを使ったAndroidの開発フローの効率化とtips
ymnder
1
1.4k
Introduction to new features of Google Play Billing
ymnder
2
320
運用から学ぶPlay Billing Library
ymnder
2
750
What’s new in Google Play Billing v1.2
ymnder
0
730
詳解定期購入
ymnder
7
6.5k
社内向けライブラリを設計・運用する話
ymnder
0
1.1k
Other Decks in Programming
See All in Programming
組込みだけじゃない!TinyGo で始める無料クラウド開発入門
otakakot
0
230
技術的負債の正体を知って向き合う / Facing Technical Debt
irof
0
160
そのpreloadは必要?見過ごされたpreloadが技術的負債として爆発した日
mugitti9
2
3.3k
CSC305 Lecture 05
javiergs
PRO
0
210
その面倒な作業、「Dart」にやらせませんか? Flutter開発者のための業務効率化
yordgenome03
1
120
CSC509 Lecture 03
javiergs
PRO
0
330
Six and a half ridiculous things to do with Quarkus
hollycummins
0
170
Go言語はstack overflowの夢を見るか?
logica0419
0
190
PHPに関数型の魂を宿す〜PHP 8.5 で実現する堅牢なコードとは〜 #phpcon_hiroshima / phpcon-hiroshima-2025
shogogg
1
150
Advance Your Career with Open Source
ivargrimstad
0
490
Django Ninja による API 開発効率化とリプレースの実践
kashewnuts
0
1.3k
Things You Thought You Didn’t Need To Care About That Have a Big Impact On Your Job
hollycummins
0
220
Featured
See All Featured
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
Making Projects Easy
brettharned
119
6.4k
Designing for Performance
lara
610
69k
How STYLIGHT went responsive
nonsquared
100
5.8k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Why Our Code Smells
bkeepers
PRO
339
57k
Site-Speed That Sticks
csswizardry
11
900
Bash Introduction
62gerente
615
210k
Six Lessons from altMBA
skipperchong
28
4k
Music & Morning Musume
bryan
46
6.8k
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