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
1.2k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Lithoを使ってみた
2017/05/09 shibuya.apk #14
ymnder
May 09, 2017
More Decks by ymnder
See All by ymnder
What’s new in Google Play's billing system
ymnder
1
430
Deep Linksをはじめよう
ymnder
0
520
Introduction to Wear OS Application Development
ymnder
0
620
CircleCIを使ったAndroidの開発フローの効率化とtips
ymnder
1
1.4k
Introduction to new features of Google Play Billing
ymnder
2
370
運用から学ぶPlay Billing Library
ymnder
2
810
What’s new in Google Play Billing v1.2
ymnder
0
790
詳解定期購入
ymnder
7
6.9k
社内向けライブラリを設計・運用する話
ymnder
0
1.2k
Other Decks in Programming
See All in Programming
komatsuna「分散システムにおけるバグ分析手法」
komatsunaqa
0
290
【デモ】Kiroで体験する仕様駆動開発|設計からコーディングまでAIと進める開発フロー
cmkudo
0
500
レビュー履歴をAIに食わせて、 Compose移行を加速するs
shihochan
0
230
思考垂れ流し開発 ~音声入力 × AIエージェント × 開発ハーネスによる試行錯誤~
npostring
0
410
まずはプロンプトガイドを読もう、話はそれからだ
kiakiraki
1
230
関東Kaggler会_NVIDIA_Nemotron_コンペ_振り返り
rick_ds
0
730
書籍「プロフェッショナルAI駆動開発」紹介スライド
juntaromatsumoto
0
780
Go を使い始めて 2 ヶ月の学び / My first two months with Go
contour_gara
0
390
ALB ログから Trace を気合で繋げる技術
fohte
7
770
Go 1.27 における memory allocation の高速化
andpad
0
350
業務時間外もAIに働いてもらう話
colorful12
2
8.7k
いまどきの Codex で開発する visionOS アプリの開発スタイルについて
karad
0
170
Featured
See All Featured
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.6k
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.8k
Paper Plane
katiecoart
PRO
2
53k
From π to Pie charts
rasagy
0
330
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
430
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
2
4.3k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Statistics for Hackers
jakevdp
799
230k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
エンジニアに許された特別な時間の終わり
watany
108
250k
Documentation Writing (for coders)
carmenintech
77
5.5k
Faster Mobile Websites
deanohume
310
32k
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