Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
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.4k
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
630
Building offline first apps
saketme
1
250
Other Decks in Programming
See All in Programming
著者と進める!『AIと個人開発したくなったらまずCursorで要件定義だ!』
yasunacoffee
0
160
AtCoder Conference 2025「LLM時代のAHC」
imjk
2
580
SwiftUIで本格音ゲー実装してみた
hypebeans
0
500
新卒エンジニアのプルリクエスト with AI駆動
fukunaga2025
0
230
PC-6001でPSG曲を鳴らすまでを全部NetBSD上の Makefile に押し込んでみた / osc2025hiroshima
tsutsui
0
170
リリース時」テストから「デイリー実行」へ!開発マネージャが取り組んだ、レガシー自動テストのモダン化戦略
goataka
0
140
チームをチームにするEM
hitode909
0
380
AIエージェントの設計で注意するべきポイント6選
har1101
5
2.3k
Deno Tunnel を使ってみた話
kamekyame
0
240
AIコーディングエージェント(skywork)
kondai24
0
200
Canon EOS R50 V と R5 Mark II 購入でみえてきた最近のデジイチ VR180 事情、そして VR180 静止画に活路を見出すまで
karad
0
140
Implementation Patterns
denyspoltorak
0
120
Featured
See All Featured
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Prompt Engineering for Job Search
mfonobong
0
130
The Illustrated Children's Guide to Kubernetes
chrisshort
51
51k
Making Projects Easy
brettharned
120
6.5k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
170
A better future with KSS
kneath
240
18k
Exploring anti-patterns in Rails
aemeredith
2
200
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Thoughts on Productivity
jonyablonski
73
5k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.6k
Writing Fast Ruby
sferik
630
62k
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?