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
Deflating the LayoutInflater
Search
Saket Narayan
August 28, 2016
Programming
5
1.3k
Deflating the LayoutInflater
https://droidconin.talkfunnel.com/2016/86-deflating-the-layoutinflater
Saket Narayan
August 28, 2016
Tweet
Share
More Decks by Saket Narayan
See All by Saket Narayan
IllegalStateException: Can not perform this action after onSaveInstanceState
saketme
5
610
Building offline first apps
saketme
1
230
Other Decks in Programming
See All in Programming
レガシーな Android アプリのリアーキテクチャ戦略
oidy
1
170
Universal Linksの実装方法と陥りがちな罠
kaitokudou
1
220
Snowflake x dbtで作るセキュアでアジャイルなデータ基盤
tsoshiro
2
430
Boost Performance and Developer Productivity with Jakarta EE 11
ivargrimstad
0
850
Golang と Erlang
taiyow
8
1.9k
Kubernetes for Data Engineers: Building Scalable, Reliable Data Pipelines
sucitw
1
200
Tuning GraphQL on Rails
pyama86
2
1k
飲食業界向けマルチプロダクトを実現させる開発体制とリアルな現状
hiroya0601
1
390
Vitest Browser Mode への期待 / Vitest Browser Mode
odanado
PRO
2
1.7k
Kaigi on Rails 2024 - Rails APIモードのためのシンプルで効果的なCSRF対策 / kaigionrails-2024-csrf
corocn
5
3.4k
Honoの来た道とこれから
yusukebe
19
3k
ECSのサービス間通信 4つの方法を比較する 〜Canary,Blue/Greenも添えて〜
tkikuc
11
2.3k
Featured
See All Featured
Testing 201, or: Great Expectations
jmmastey
38
7k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
167
49k
It's Worth the Effort
3n
183
27k
Code Review Best Practice
trishagee
64
17k
Producing Creativity
orderedlist
PRO
341
39k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
9
680
Speed Design
sergeychernyshev
24
570
How To Stay Up To Date on Web Technology
chriscoyier
788
250k
GraphQLとの向き合い方2022年版
quramy
43
13k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
6.9k
How to Ace a Technical Interview
jacobian
275
23k
Building Better People: How to give real-time feedback that sticks.
wjessup
363
19k
Transcript
Deflating the LayoutInflater Saket • Uncommon
Parts 1. What and how 2. Applications
Part 1, What is LayoutInflater
Converts View hierarchies written in XML into Java objects XML
<TextView android:layout_width="wrap_content" android:layout_height=“wrap_content" /> Java public class TextView extends View { ... }
Common Usages
Fragments @Override public View onCreateView(LayoutInflater, ViewGroup, Bundle) { return inflater.inflate(
R.layout.fragment_layout, container, false ); }
ViewHolders @Override public ViewHolder onCreateViewHolder(ViewGroup, int) { return new ViewHolder(inflater.inflate(
R.layout.fragment_layout, container, false )); }
Activities @Override protected void onCreate(Bundle savedState) { super.onCreate(savedState); setContentView(R.layout.activity_main); }
PhoneWindow.java (or AppCompatDelegateImplV7.java) @Override public void setContentView(int layoutRes) { mLayoutInflater.inflate(layoutRes,
mParent); }
How it works
LayoutInflater#inflate() A. XmlPullParser B. AttributeSet C. Creating View objects
LayoutInflater#inflate() A. XmlPullParser GSON, Moshi for JSON is the same
as XmlPullParser for XML
LayoutInflater#inflate() B. AttributeSet <ImageView android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/ic_done" android:contentDescription="Save" />
LayoutInflater#inflate() B. AttributeSet <ImageView android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/ic_done" android:contentDescription="Save" />
LayoutInflater#inflate() B. AttributeSet <ImageView android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/ic_done" android:contentDescription="Save" />
LayoutInflater#inflate() B. AttributeSet <ImageView android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/ic_done" android:contentDescription="Save" />
LayoutInflater#inflate() B. AttributeSet <ImageView android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/ic_done" android:contentDescription="Save" />
LayoutInflater#inflate() B. AttributeSet <ImageView android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/ic_done" android:contentDescription="Save" />
LayoutInflater#inflate() B. AttributeSet <ImageView android:layout_width="@dimen/list_icon" android:layout_height="@dimen/list_icon" android:src="@drawable/ic_done" android:contentDescription="Save" /> res/values/dimens.xml
LayoutInflater#inflate() B. AttributeSet Figures precedence of attributes <ImageView style="@style/Button.Save" android:layout_width="100dp"
android:layout_height="100dp" android:src=“@drawable/ic_done" />
LayoutInflater#inflate() B. AttributeSet Figures precedence of attributes <ImageView style="@style/Button.Save" android:layout_width="100dp"
android:layout_height="100dp" android:src=“@drawable/ic_done" />
LayoutInflater#inflate() B. AttributeSet Figures precedence of attributes <style name="Button.Save"> <item
name="android:layout_width">200dp</item> <item name="android:layout_height">200dp</item> </style>
LayoutInflater#inflate() B. AttributeSet Figures precedence of attributes <ImageView style="@style/Button.Save" android:layout_width="100dp"
android:layout_height="100dp" android:src=“@drawable/ic_done" />
Finding a View’s source Creating the View object using Reflection
LayoutInflater#inflate() C. Creating View Objects
Finding a View’s source Creating the View object using Reflection
LayoutInflater#inflate() C. Creating View Objects
Black magic Slow Reflection?
Delegate creation to “Factories” Instantiate View by itself (if #1
fails) Creating View Objects
Delegate creation to “Factories” Instantiate View by itself (if #1
fails) context.getClassLoader().loadClass(); Creating View Objects
Delegate creation to “Factories” Instantiate View by itself a) Custom
View b) Framework View Creating View Objects
a) Custom View: <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height=“match_parent" /> Creating View Objects
a) Custom View: Class<RecyclerView> clazz = ClassLoader#loadClass( "android.support.v7.widget.RecyclerView" ); RecyclerView
view = clazz.getConstructor().newInstance(); Creating View Objects
a) Framework View: <TextView android:layout_width="match_parent" android:layout_height="match_parent" /> Creating View Objects
a) Custom View: Class<TextView> clazz = ClassLoader#loadClass( "TextView" ); Creating
View Objects
a) Custom View: Class<TextView> clazz = ClassLoader#loadClass( "android.widget.TextView" ); Creating
View Objects
a) Custom View: Class<TextView> clazz = ClassLoader#loadClass( "android.widget.TextView" ); TextView
view = clazz.getConstructor().newInstance(); Creating View Objects
Delegate creation to “Factories” Instantiate View by itself Creating View
Objects
LayoutInflater Factories
Installing a Factory @Override protected void onCreate(Bundle savedState) { getLayoutInflater().setFactory2(...);
super.onCreate(savedState); }
Common Factories a) Activity public class Activity extends ContextThemeWrapper implements
LayoutInflater.Factory2 { }
Common Factories a) Activity
Common Factories a) Activity <LinearLayout> <fragment android:name="is.uncommon.ShinyFragment" android:layout_width="match_parent" android:layout_height="match_parent" />
</LinearLayout>
Common Factories a) Activity <LinearLayout> <fragment android:name="is.uncommon.ShinyFragment" android:layout_width="match_parent" android:layout_height="match_parent" />
</LinearLayout>
Common Factories b) AppCompat Continued in Part 2.
Part 2, Hooking into LayoutInflater
example, AppCompat How it back-ports material design to pre-Lollipop devices
android:theme
AppCompat Kitkat
AppCompat Kitkat
AppCompat <Button android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/custom_btn" /> custom_btn.xml <selector> @drawable/custom_btn_normal @drawable/custom_btn_focussed
@drawable/custom_btn_pressed </selector>
AppCompat <Button android:layout_width="match_parent" android:layout_height="match_parent" android:theme="@style/CustomButtonTheme" /> styles.xml <style name="CustomButtonTheme"> <item
name=“colorButtonNormal”>#09F</item> <item name=“colorControlHighlight">#07F</item> </style>
example, AppCompat AppCompatActivity @Override protected void onCreate(Bundle savedState) { installViewFactory();
... }
example, AppCompat AppCompatViewInflater.java implements LayoutInflater.Factory2 { ... }
example, AppCompat AppCompatViewInflater.java public View onCreateView(String viewName, ...) { if
("TextView".equals(viewName) { return new AppCompatTextView(); } ... }
example, AppCompat
example, Calligraphy How it applies custom fonts without using any
custom Views. <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" fontPath="fonts/Roboto-Bold.ttf" />
example, Calligraphy class CalligraphyLayoutInflater extends LayoutInflater { ... }
example, Calligraphy @Override View onCreateView(String name, AttributeSet) { View view
= super.onCreateView(...); if (view instanceOf TextView) { applyTypeface((TextView) view); } return view; }
example, Calligraphy @Override View onCreateView(String name, AttributeSet) { View view
= super.onCreateView(...); if (view instanceOf TextView) { applyTypeface((TextView) view); } return view; }
What if… We could do this? <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" formatter="IndianRupees"
/>
What if… We could do this? <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" formatter="IndianRupees"
/> 250000
What if… We could do this? <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" formatter="IndianRupees"
/> Ũ2,50,000
What if… Or this? <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" formatter="CreditCardNumber" />
What if… Or this? <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" formatter="CreditCardNumber" /> 4652
3700 0055 5032
What if… Or this? <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" formatter="CreditCardNumber" /> 3400
123456 000032
What if… Or maybe this? <FrameLayout android:layout_width="wrap_content" android:layout_height=“wrap_content" paddings="16dp 20dp"
/>
WHAT IF I TOLD YOU IT’S POSSIBLE TO DO THAT?
Introducing, Balloon!
Balloon interface BalloonAttributeListener { void onApplyAttribute( View view, int attributeResId,
Object attributeValue ); }
Application#onCreate() Balloon.config() .registerAttr(R.attr.formatter, FormatterAttrListener) .build(); Balloon
Application#onCreate() Balloon.config() .registerAttr(R.attr.formatter, FormatterAttrListener) .build(); Balloon
Application#onCreate() Balloon.config() .registerAttr(R.attr.formatter, FormatterAttrListener) .build(); Balloon
Balloon class FormatterAttrListener implements BalloonAttributeListener <> { @Override void onApplyAttribute(EditText
view, int attrResId, String attrValue) { if ("IndianRupees".equals(attrValue)) { // Add rupee symbol and format digits } } }
Pros Composition > Inheritance Can be used for multiple types
of Views Quick
Cons “Experimental” No layout preview in Android Studio
Working class BalloonLayoutInflater extends LayoutInflater { ... }
Challenges Activity getLayoutInflater() -> return LayoutInflater
Challenges Activity getLayoutInflater() -> return LayoutInflater -> return BalloonLayoutInflater
Challenges public class BalloonContext extends Context { ... }
Challenges Activity @Override void attachBaseContext(Context base) { super.attachBaseContext(BalloonContext.wrap(base)); }
Challenges Activity @Override void attachBaseContext(Context base) { super.attachBaseContext(BalloonContext.wrap(base)); }
Challenges BalloonContext @Override Object getSystemService(String name) { if (LAYOUT_INFLATER_SERVICE.equals(name)) {
return new BalloonLayoutInflater(); } return super.getSystemService(name); }
Challenges BalloonContext @Override Object getSystemService(String name) { if (LAYOUT_INFLATER_SERVICE.equals(name)) {
return new BalloonLayoutInflater(); } return super.getSystemService(name); }
Challenges Activity getLayoutInflater() -> return BalloonLayoutInflater
saket.me/droidcon
Learnings Layout inflation is a slow process. Complex layouts can
affect an Activity’s startup time.
Learnings Why non-framework Views require their fully qualified names in
XML whereas framework Views don’t. <is.uncommon.FancyCustomView /> vs. <TextView />
That’s all folks!
Uncommon hello @ uncommon.is
Questions?