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
590
Building offline first apps
saketme
1
230
Other Decks in Programming
See All in Programming
Introduction of Happy Eyeballs Version 2 (RFC8305) to the Socket library
coe401_
1
220
SDCon2024: Enabling DevOps and Team Topologies thru architecture: architecting for fast flow
cer
PRO
0
780
【Go言語】golangci-lintの使い方
tomo1227
0
270
Play Billing Library 7.0.0 変更点まとめ@potatotips#88
kako351
0
160
入社1ヶ月でここまでやった!Findy Toolsインフラ支援の最適化
rvirus0817
6
1.4k
HMSコンペ 11th Solution (team : kansai-kaggler)
t88
1
680
CSC307 Lecture 08
javiergs
PRO
0
330
CSC307 Lecture 09
javiergs
PRO
1
500
20240706_CDKConf
takuyay0ne
0
1.2k
「2024年版 Kotlin サーバーサイドプログラミング実践開発」の補講 〜O/Rマッパー編〜
n_takehata
2
260
The rollercoaster of releasing an Android, iOS, and macOS app with Kotlin Multiplatform | droidcon Berlin
prof18
0
110
Rubyのパフォーマンスプロファイリングの改善 / Enhancing performance profiling for Ruby
osyoyu
1
410
Featured
See All Featured
How to Think Like a Performance Engineer
csswizardry
4
590
Building an army of robots
kneath
301
42k
Docker and Python
trallard
37
2.9k
Building Applications with DynamoDB
mza
89
5.8k
How GitHub (no longer) Works
holman
305
140k
A Tale of Four Properties
chriscoyier
155
22k
Agile that works and the tools we love
rasmusluckow
325
20k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
502
140k
Teambox: Starting and Learning
jrom
130
8.6k
WebSockets: Embracing the real-time Web
robhawkes
59
7.2k
Imperfection Machines: The Place of Print at Facebook
scottboms
262
13k
The Language of Interfaces
destraynor
151
23k
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?