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
300
Deep Linksをはじめよう
ymnder
0
370
Introduction to Wear OS Application Development
ymnder
0
500
CircleCIを使ったAndroidの開発フローの効率化とtips
ymnder
1
1.3k
Introduction to new features of Google Play Billing
ymnder
2
300
運用から学ぶPlay Billing Library
ymnder
2
740
What’s new in Google Play Billing v1.2
ymnder
0
700
詳解定期購入
ymnder
7
6.3k
社内向けライブラリを設計・運用する話
ymnder
0
1k
Other Decks in Programming
See All in Programming
Fluent UI Blazor 5 (alpha)の紹介
tomokusaba
0
150
私の愛したLaravel 〜レールを超えたその先へ〜
kentaroutakeda
12
3.6k
体得しよう!RSA暗号の原理と解読
laysakura
3
540
custom_lintで始めるチームルール管理
akaboshinit
0
160
Devinのメモリ活用の学びを自社サービスにどう組み込むか?
itarutomy
0
1.8k
海外のアプリで見かけたかっこいいTransitionを真似てみる
shogotakasaki
1
120
アーキテクトと美学 / Architecture and Aesthetics
nrslib
12
3.2k
아직도 SOLID 를 '글'로만 알고 계신가요?
sh1mj1
0
360
データベースエンジニアの仕事を楽にする。PgAssistantの紹介
nnaka2992
9
4.3k
パスキーのすべて / 20250324 iddance Lesson.5
kuralab
0
140
snacks.nvim内のセットアップ不要なプラグインを紹介 / introduce_snacks_nvim
uhooi
0
360
複数ドメインに散らばってしまった画像…! 運用中のPHPアプリに後からCDNを導入する…!
suguruooki
0
440
Featured
See All Featured
4 Signs Your Business is Dying
shpigford
183
22k
How to Think Like a Performance Engineer
csswizardry
22
1.5k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
29
2k
BBQ
matthewcrist
88
9.5k
Optimising Largest Contentful Paint
csswizardry
35
3.2k
Done Done
chrislema
183
16k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
8
700
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
40
2k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
Build your cross-platform service in a week with App Engine
jlugia
229
18k
Typedesign – Prime Four
hannesfritz
41
2.6k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
30
1.1k
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