blob: 6a933d82862e3d7bf4f6fae5484d5ddcbf3e3a4d [file] [log] [blame]
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001page.title=Data Binding Guide
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07002page.tags="databinding", "layouts"
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07003@jd:body
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07004
5<div class="wrap">
6<p class="caution" style="background-color:#fffdeb;">
7The <strong>Android Data Binding Library</strong> is available as a <strong>developer
8preview</strong>. Expression syntax and behaviors may change prior to the full release
9of the library, currently planned for Q3 2015. If you have feedback or want to report
10issues, please use the <a href="https://code.google.com/p/android-developer-preview/">issue
11tracker</a>. Stay tuned for more information about Data Binding and examples of how to use it. </a>
12</p>
13</div>
14<div id="qv-wrapper">
15 <div id="qv">
16 <h2>
17 In this document:
18 </h2>
19
20 <ol>
21 <li>
22 <a href="#build_environment">Build Environment</a>
23 </li>
24
25 <li>
26 <a href="#data_binding_layout_files">Data Binding Layout Files</a>
27 <ol>
28 <li>
29 <a href="writing_expressions">Writing your first data binding
30 expressions</a>
31 </li>
32
33 <li>
34 <a href="data_object">Data Object</a>
35 </li>
36
37 <li>
38 <a href="binding_data">Binding Data</a>
39 </li>
40 </ol>
41 </li>
42
43 <li>
44 <a href="#layout_details">Layout Details</a>
45 <ol>
46 <li>
47 <a href="imports">Imports</a>
48 </li>
49
50 <li>
51 <a href="variables">Variables</a>
52 </li>
53
54 <li>
55 <a href="custom_binding_class_names">Custom Binding Class Names</a>
56 </li>
57
58 <li>
59 <a href="includes">Includes</a>
60 </li>
61
62 <li>
63 <a href="expression_language">Expression Language</a>
64 </li>
65 </ol>
66 </li>
67
68 <li>
69 <a href="#data_objects">Data Objects</a>
70 <ol>
71 <li>
72 <a href="observable_objects">Observable Objects</a>
73 </li>
74
75 <li>
76 <a href="observablefields">ObservableFields</a>
77 </li>
78
79 <li>
80 <a href="observable_collections">Observable Collections</a>
81 </li>
82 </ol>
83 </li>
84
85 <li>
86 <a href="#generated_binding">Generated Binding</a>
87 <ol>
88 <li>
89 <a href="creating">Creating</a>
90 </li>
91
92 <li>
93 <a href="views_with_ids">Views With IDs</a>
94 </li>
95
96 <li>
97 <a href="variables">Variables</a>
98 </li>
99
100 <li>
101 <a href="viewstubs">ViewStubs</a>
102 </li>
103
104 <li>
105 <a href="advanced_binding">Advanced Binding</a>
106 </li>
107 </ol>
108 </li>
109
110 <li>
111 <a href="#attribute_setters">Attribute Setters</a>
112 <ol>
113 <li>
114 <a href="automatic_setters">Automatic Setters</a>
115 </li>
116
117 <li>
118 <a href="renamed_setters">Renamed Setters</a>
119 </li>
120
121 <li>
122 <a href="custom_setters">Custom Setters</a>
123 </li>
124 </ol>
125 </li>
126
127 <li>
128 <a href="#converters">Converters</a>
129 <ol>
130 <li>
131 <a href="object_conversions">Object Conversions</a>
132 </li>
133
134 <li>
135 <a href="custom_conversions">Custom Conversions</a>
136 </li>
137 </ol>
138 </li>
139 </ol>
140 </div><!-- qv -->
141</div><!-- qv-wrapper -->
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700142
143
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700144<p>
145 This document explains how to use the Data Binding Library to write
146 declarative layouts and minimize the glue code necessary to bind your
147 application logic and layouts.
148</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700149
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700150<h2 id="build_environment">
151 Build Environment
152</h2>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700153
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700154<p>
155 <strong>Setting Up Work Environment:</strong>
156</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700157
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700158<p>
159 To set up your application to use data binding, add data binding to the class
160 path of your build gradle file, right below "android".
161</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700162
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700163<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700164 dependencies {
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700165 classpath <strong>"com.android.tools.build:gradle:1.2.3"
166 </strong>classpath <strong>"com.android.databinding:dataBinder:</strong>1.0-rc0"
167 }
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700168}
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700169</pre>
170<p>
171 Then make sure jcenter is in the repositories list for your sub projects.
172</p>
173
174<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700175allprojects {
176 repositories {
177 jcenter()
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700178 }
179}
180</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700181<p>
182 In each module you want to use data binding, apply the plugin right after
183 android plugin
184</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700185
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700186<pre>
187apply plugin: ‘com.android.application&apos;
188apply plugin: &apos;<strong>com.android.databinding</strong>&apos;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700189</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700190<p>
191 The data binding plugin is going to add necessary <strong>provided</strong>
192 and <strong>compile configuration</strong> dependencies to your project.
193</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700194
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700195<h2 id="data_binding_layout_files">
196 Data Binding Layout Files
197</h2>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700198
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700199<h3 id="writing_expressions">
200 Writing your first data binding expressions
201</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700202
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700203<p>
204 Data-binding layout files are slightly different and start with a root tag of
205 <strong>layout</strong> followed by a <strong>data</strong> element and a
206 <strong>view</strong> root element. This view element is what your root would
207 be in a non-binding layout file. A sample file looks like this:
208</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700209
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700210<pre>
211<em>&lt;?</em><strong>xml version="1.0" encoding="utf-8"</strong><em>?&gt;
212</em>&lt;<strong>layout xmlns:android="http://schemas.android.com/apk/res/android"</strong>&gt;
213 &lt;<strong>data</strong>&gt;
214 &lt;<strong>variable name="user" type="com.example.User"</strong>/&gt;
215 &lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700216 &lt;<strong>LinearLayout
217 android:orientation="vertical"
218 android:layout_width="match_parent"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700219 android:layout_height="match_parent"</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700220 &lt;<strong>TextView android:layout_width="wrap_content"
221 android:layout_height="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700222 android:text="&commat;{user.firstName}"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700223 &lt;<strong>TextView android:layout_width="wrap_content"
224 android:layout_height="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700225 android:text="&commat;{user.lastName}"</strong>/&gt;
226 &lt;/<strong>LinearLayout</strong>&gt;
227&lt;/<strong>layout</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700228</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700229<p>
230 The user <strong>variable</strong> within <strong>data</strong> describes a
231 property that may be used within this layout.
232</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700233
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700234<pre>
235&lt;<strong>variable name="user" type="com.example.User"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700236</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700237<p>
238 Expressions within the layout are written in the attribute properties using
239 the “<code>&commat;{}</code>” syntax. Here, the TextView’s text is set to the
240 firstName property of user:
241</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700242
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700243<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700244&lt;<strong>TextView android:layout_width="wrap_content"
245 android:layout_height="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700246 android:text="&commat;{user.firstName}"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700247</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700248<h3 id="data_object">
249 Data Object
250</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700251
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700252<p>
253 Let’s assume for now that you have a plain-old Java object (POJO) for User:
254</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700255
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700256<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700257<strong>public class </strong>User {
258 <strong>public final </strong>String <strong>firstName</strong>;
259 <strong>public final </strong>String <strong>lastName</strong>;
260 <strong>public </strong>User(String firstName, String lastName) {
261 <strong>this</strong>.<strong>firstName </strong>= firstName;
262 <strong>this</strong>.<strong>lastName </strong>= lastName;
263 }
264}
265</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700266<p>
267 This type of object has data that never changes. It is common in applications
268 to have data that is read once and never changes thereafter. It is also
269 possible to use a JavaBeans objects:
270</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700271
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700272<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700273<strong>public class </strong>User {
274 <strong>private final </strong>String <strong>firstName</strong>;
275 <strong>private final </strong>String <strong>lastName</strong>;
276 <strong>public </strong>User(String firstName, String lastName) {
277 <strong>this</strong>.<strong>firstName </strong>= firstName;
278 <strong>this</strong>.<strong>lastName </strong>= lastName;
279 }
280 <strong>public </strong>String getFirstName() {
281 <strong>return this</strong>.<strong>firstName</strong>;
282 }
283 <strong>public </strong>String getLastName() {
284 <strong>return this</strong>.<strong>lastName</strong>;
285 }
286}
287</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700288<p>
289 From the perspective of data binding, these two classes are equivalent. The
290 expression <strong><code>&commat;{user.firstName}</code></strong> used for
291 the TextView’s <strong><code>android:text</code></strong> attribute will
292 access the <strong><code>firstName</code></strong> field in the former class
293 and the <code>getFirstName()</code> method in the latter class.
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700294</p>
295
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700296<h3 id="binding_data">
297 Binding Data
298</h3>
299
300<p>
301 By default, a Binding class will be generated based on the name of the layout
302 file, converting it to Pascal case and suffixing “Binding” to it. The above
303 layout file was <code>activity_main.xml</code> so the generate class was
304 <code>ActivityMainBinding</code>. This class holds all the bindings from the
305 layout properties (e.g. the <code>user</code> variable) to the layout’s Views
306 and knows how to assign values for the binding expressions.The easiest means
307 for creating the bindings is to do it while inflating:
308</p>
309
310<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700311&commat;Override
312<strong>protected void </strong>onCreate(Bundle savedInstanceState) {
313 <strong>super</strong>.onCreate(savedInstanceState);
314 ActivityMainBinding binding = DataBindingUtil.<em>setContentView</em>(<strong>this</strong>, R.layout.<em><strong>main_activity</strong></em>);
315 User user = <strong>new </strong>User(<strong>"Test"</strong>, <strong>"User"</strong>);
316 binding.setUser(user);
317}
318</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700319<p>
320 You’re done! Run the application and you’ll see Test User in the UI.
321 Alternatively, you can get the view via:
322</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700323
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700324<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700325MainActivityBinding binding = MainActivityBinding.<em>inflate</em>(getLayoutInflater());
326</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700327<p>
328 If you are using data binding items inside a ListView or RecyclerView
329 adapter, you may prefer to use:
330</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700331
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700332<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700333ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup,
334false);
335//or
336ListItemBinding binding = DataBindingUtil.<em>inflate</em>(layoutInflater, R.layout.<em><strong>list_item</strong></em>, viewGroup, <strong>false</strong>);
337</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700338<h2 id="layout_details">
339 Layout Details
340</h2>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700341
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700342<h3 id="imports">
343 Imports
344</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700345
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700346<p>
347 Zero or more <strong><code>import</code></strong> elements may be used inside
348 the <strong><code>data</code></strong> element. These allow easy reference to
349 classes inside your layout file, just like in Java.
350</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700351
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700352<pre>
353&lt;<strong>data</strong>&gt;
354 &lt;<strong>import type="android.view.View"</strong>/&gt;
355&lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700356</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700357<p>
358 Now, View may be used within your binding expression:
359</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700360
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700361<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700362&lt;<strong>TextView
363 android:text="&commat;{user.lastName}"
364 android:layout_width="wrap_content"
365 android:layout_height="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700366 android:visibility="&commat;{user.isAdult ? View.VISIBLE : View.GONE}"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700367</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700368<p>
369 When there are class name conflicts, one of the classes may be renamed to an
370 “alias:”
371</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700372
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700373<pre>
374&lt;<strong>import type="android.view.View"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700375&lt;<strong>import type="com.example.real.estate.View"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700376 alias="Vista"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700377</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700378<p>
379 Now, <strong><code>Vista</code></strong> may be used to reference the
380 <code>com.example.real.estate.View</code> and
381 <strong><code>View</code></strong> may be used to reference
382 <code>android.view.View</code> within the layout file. Imported types may be
383 used as type references in variables and expressions:
384</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700385
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700386<pre>
387&lt;<strong>data</strong>&gt;
388 &lt;<strong>import type="com.example.User"</strong>/&gt;
389 &lt;<strong>import type="java.util.List"</strong>/&gt;
390 &lt;<strong>variable name="user" type="User"</strong>/&gt;
391 &lt;<strong>variable name="userList" type="List&amp;lt;User&gt;"</strong>/&gt;
392 &lt;/<strong>data</strong>&gt;
393</pre>
394<p class="note">
395 <strong>Note</strong>: Android Studio does not yet handle imports so the
396 autocomplete for imported variables may not work in your IDE. Your
397 application will still compile fine and you can work around the IDE issue by
398 using fully qualified names in your variable definitions.
399</p>
400
401<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700402&lt;<strong>TextView
403 android:text="&commat;{((User)(user.connection)).lastName}"
404 android:layout_width="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700405 android:layout_height="wrap_content"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700406</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700407<p>
408 Imported types may also be used when referencing static fields and methods in
409 expressions:
410</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700411
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700412<pre>
413&lt;<strong>data</strong>&gt;
414 &lt;<strong>import type="com.example.MyStringUtils"</strong>/&gt;
415 &lt;<strong>variable name="user" type="com.example.User"</strong>/&gt;
416&lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700417
418&lt;<strong>TextView
419 android:text="&commat;{MyStringUtils.capitalize(user.lastName)}"
420 android:layout_width="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700421 android:layout_height="wrap_content"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700422</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700423<p>
424 Just as in Java, <code>java.lang.*</code> is imported automatically.
425</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700426
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700427<h3 id="variables">
428 Variables
429</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700430
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700431<p>
432 Any number of <strong><code>variable</code></strong> elements may be used
433 inside the <strong><code>data</code></strong> element. Each
434 <strong><code>variable</code></strong> element describes a property that may
435 be set on the layout to be used in binding expressions within the layout
436 file.
437</p>
438
439<pre>
440&lt;<strong>data</strong>&gt;
441 &lt;<strong>import type="android.graphics.drawable.Drawable"</strong>/&gt;
442 &lt;<strong>variable name="user" type="com.example.User"</strong>/&gt;
443 &lt;<strong>variable name="image" type="Drawable"</strong>/&gt;
444 &lt;<strong>variable name="note" type="String"</strong>/&gt;
445&lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700446</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700447<p>
448 The variable types are inspected at compile time, so if a variable implements
449 <a href="#observable_objects">Observable</a> or is an <a href=
450 "#observable_collections">observable collection</a>, that should be reflected
451 in the type. If the variable is a base class or interface that does not
452 implement the Observable* interface, the variables will <strong>not
453 be</strong> observed!
454</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700455
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700456<p>
457 When there are different layout files for various configurations (e.g.
458 landscape or portrait), the variables will be combined. There must not be
459 conflicting variable definitions between these layout files.
460</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700461
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700462<p>
463 The generated binding class will have a setter and getter for each of the
464 described variables. The variables will take the default Java values until
465 the setter is called &mdash; <code>null</code> for reference types,
466 <code>0</code> for <code>int</code>, <code>false</code> for
467 <code>boolean</code>, etc.
468</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700469
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700470<h3 id="custom_binding_class_names">
471 Custom Binding Class Names
472</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700473
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700474<p>
475 By default, a Binding class is generated based on the name of the layout
476 file, starting it with upper-case, removing underscores ( _ ) and
477 capitalizing the following letter and then suffixing “Binding”. This class
478 will be placed in a databinding package under the module package. For
479 example, the layout file <code>contact_item.xml</code> will generate
480 <code>ContactItemBinding</code>. If the module package is
481 <code>com.example.my.app</code>, then it will be placed in
482 <code>com.example.my.app.databinding</code>.
483</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700484
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700485<p>
486 Binding classes may be renamed or placed in different packages by adjusting
487 the <strong><code>class</code></strong> attribute of the
488 <strong><code>data</code></strong> element. For example:
489</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700490
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700491<pre>
492&lt;<strong>data class="ContactItem"</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700493 ...
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700494&lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700495</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700496<p>
497 This generates the binding class as <code>ContactItem</code> in the
498 databinding package in the module package. If the class should be generated
499 in a different package within the module package, it may be prefixed with
500 “.”:
501</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700502
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700503<pre>
504&lt;<strong>data class=".ContactItem"</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700505 ...
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700506&lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700507</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700508<p>
509 In this case, <code>ContactItem</code> is generated in the module package
510 directly. Any package may be used if the full package is provided:
511</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700512
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700513<pre>
514&lt;<strong>data class="com.example.ContactItem"</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700515 ...
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700516&lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700517</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700518<h3 id="includes">
519 Includes
520</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700521
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700522<p>
523 Variables may be passed into an included layout&apos;s binding from the
524 containing layout by using the application namespace and the variable name in
525 an attribute:
526</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700527
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700528<pre>
529<em>&lt;?</em><strong>xml version="1.0" encoding="utf-8"</strong><em>?&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700530</em>&lt;<strong>layout xmlns:android="http://schemas.android.com/apk/res/android"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700531</strong> <strong> xmlns:bind="http://schemas.android.com/apk/res-auto"</strong>&gt;
532 &lt;<strong>data</strong>&gt;
533 &lt;<strong>variable name="user" type="com.example.User"</strong>/&gt;
534 &lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700535 &lt;<strong>LinearLayout
536 android:orientation="vertical"
537 android:layout_width="match_parent"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700538 android:layout_height="match_parent"</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700539 &lt;<strong>include layout="&commat;layout/name"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700540 bind:user="&commat;{user}"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700541 &lt;<strong>include layout="&commat;layout/contact"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700542 bind:user="&commat;{user}"</strong>/&gt;
543 &lt;/<strong>LinearLayout</strong>&gt;
544&lt;/<strong>layout</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700545</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700546<p>
547 Here, there must be a <code>user</code> variable in both the
548 <code>name.xml</code> and <code>contact.xml</code> layout files.
549</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700550
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700551<h3 id="expression_language">
552 Expression Language
553</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700554
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700555<h4 id="common_features">
556 Common Features
557</h4>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700558
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700559<p>
560 The expression language looks a lot like a Java expression. These are the
561 same:
562</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700563
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700564<ul>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700565 <li>Mathematical <strong><code>+ - / * %</code></strong>
566 </li>
567
568 <li>String concatenation <strong><code>+</code></strong>
569 </li>
570
571 <li>
572 <code>L</code>ogical <strong><code>&& ||</code></strong>
573 </li>
574
575 <li>Binary <strong><code>&</code> <code>|</code> <code>^</code></strong>
576 </li>
577
578 <li>Unary <strong><code>+ - ! ~</code></strong>
579 </li>
580
581 <li>Shift <strong><code>&gt;&gt; &gt;&gt;&gt; &lt;&lt;</code></strong>
582 </li>
583
584 <li>Comparison <strong><code>== &gt; &lt; &gt;= &lt;=</code></strong>
585 </li>
586
587 <li>
588 <strong><code>instanceof</code></strong>
589 </li>
590
591 <li>Grouping <strong><code>()</code></strong>
592 </li>
593
594 <li>Literals - character, String, numeric, <strong><code>null</code></strong>
595 </li>
596
597 <li>Cast
598 </li>
599
600 <li>Method calls
601 </li>
602
603 <li>Field access
604 </li>
605
606 <li>Array access <strong><code>[]</code></strong>
607 </li>
608
609 <li>Ternary operator <strong><code>?:</code></strong>
610 </li>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700611</ul>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700612
613<p>
614 Examples:
615</p>
616
617<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700618<strong>android:text="&commat;{String.valueOf(index + 1)}"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700619android:visibility="&commat;{age &amp;lt; 13 ? View.GONE : View.VISIBLE}"
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700620android:transitionName=&apos;&commat;{"image_" + id}&apos;</strong>
621</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700622<h4 id="missing_operations">
623 Missing Operations
624</h4>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700625
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700626<p>
627 A few operations are missing from the expression syntax that you can use in
628 Java.
629</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700630
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700631<ul>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700632 <li>
633 <strong><code>this</code></strong>
634 </li>
635
636 <li>
637 <strong><code>super</code></strong>
638 </li>
639
640 <li>
641 <strong><code>new</code></strong>
642 </li>
643
644 <li>Explicit generic invocation
645 </li>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700646</ul>
647
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700648<h4 id="null_coalescing_operator">
649 Null Coalescing Operator
650</h4>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700651
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700652<p>
653 The null coalescing operator (<strong><code>??</code></strong>) chooses the
654 left operand if it is not null or the right if it is null.
655</p>
656
657<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700658<strong>android:text="&commat;{user.displayName ?? user.lastName}"</strong>
659</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700660<p>
661 This is functionally equivalent to:
662</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700663
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700664<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700665<strong>android:text="&commat;{user.displayName != null ? user.displayName : user.lastName}"</strong>
666</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700667<h4 id="property_reference">
668 Property Reference
669</h4>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700670
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700671<p>
672 The first was already discussed in the <a href=
673 "#writing_your_first_data_binding_expressions">Writing your first data
674 binding expressions</a> above: short form JavaBean references. When an
675 expression references a property on a class, it uses the same format for
676 fields, getters, and ObservableFields.
677</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700678
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700679<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700680<strong>android:text="&commat;{user.lastName}"</strong>
681</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700682<h4>
683 Avoiding NullPointerException
684</h4>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700685
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700686<p>
687 Generated data binding code automatically checks for nulls and avoid null
688 pointer exceptions. For example, in the expression
689 <code>&commat;{user.name}</code>, if <code>user</code> is null,
690 <code>user.name</code> will be assigned its default value (null). If you were
691 referencing <code>user.age</code>, where age is an <code>int</code>, then it
692 would default to 0.
693</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700694
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700695<h4 id="collections">
696 Collections
697</h4>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700698
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700699<p>
700 Common collections: arrays, lists, sparse lists, and maps, may be accessed
701 using the <code>[]</code> operator for convenience.
702</p>
703
704<pre>
705&lt;<strong>data</strong>&gt;
706 &lt;<strong>import type="android.util.SparseArray"</strong>/&gt;
707 &lt;<strong>import type="java.util.Map"</strong>/&gt;
708 &lt;<strong>import type="java.util.List"</strong>/&gt;
709 &lt;<strong>variable name="list" type="List&lt;String&gt;"</strong>/&gt;
710 &lt;<strong>variable name="sparse" type="SparseArray&amp;lt;String&gt;"</strong>/&gt;
711 &lt;<strong>variable name="map" type="Map&amp;lt;String, String&gt;"</strong>/&gt;
712 &lt;<strong>variable name="index" type="int"</strong>/&gt;
713 &lt;<strong>variable name="key" type="String"</strong>/&gt;
714&lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700715
716<strong>android:text="&commat;{list[index]}"
717</strong>…
718<strong>android:text="&commat;{sparse[index]}"
719</strong>…
720<strong>android:text="&commat;{map[key]}"
721</strong>
722</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700723<h4 id="string_literals">
724 String Literals
725</h4>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700726
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700727<p>
728 When using single quotes around the attribute value, it is easy to use double
729 quotes in the expression:
730</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700731
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700732<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700733<strong>android:text=&apos;&commat;{map["firstName"]}&apos;</strong>
734</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700735<p>
736 It is also possible to use double quotes to surround the attribute value.
737 When doing so, String literals should either use the &amp;quot; or back quote
738 (`).
739</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700740
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700741<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700742<strong>android:text="&commat;{map[`firstName`}"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700743android:text="&commat;{map[&amp;quot;firstName&amp;quot;]}"</strong>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700744</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700745<h4 id="resources">
746 Resources
747</h4>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700748
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700749<p>
750 It is possible to access resources as part of expressions using the normal
751 syntax:
752</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700753
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700754<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700755<strong>android:padding="&commat;{large? &commat;dimen/largePadding : &commat;dimen/smallPadding}"</strong>
756</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700757<p>
758 Format strings and plurals may be evaluated by providing parameters:
759</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700760
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700761<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700762<strong>android:text="&commat;{&commat;string/nameFormat(firstName, lastName)}"
763android:text="&commat;{&commat;plurals/banana(bananaCount)}"</strong>
764</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700765<p>
766 When a plural takes multiple parameters, all parameters should be passed:
767</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700768
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700769<pre>
770
771 Have an orange
772 Have %d oranges
773
774android:text="<strong>&commat{&commatplurals/orange(orangeCount, orangeCount)}</strong>"
775</pre>
776<p>
777 Some resources require explicit type evaluation.
778</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700779
780<table>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700781 <tr>
782 <th>
783 Type
784 </th>
785 <th>
786 Normal Reference
787 </th>
788 <th>
789 Expression Reference
790 </th>
791 </tr>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700792
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700793 <tr>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700794 <td>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700795 <pre>
796String[]
797</pre>
798 </td>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700799 <td>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700800 &commat;array
801 </td>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700802 <td>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700803 &commat;stringArray
804 </td>
805 </tr>
806
807 <tr>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700808 <td>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700809 int[]
810 </td>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700811 <td>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700812 &commat;array
813 </td>
814 <td>
815 &commat;intArray
816 </td>
817 </tr>
818
819 <tr>
820 <td>
821 TypedArray
822 </td>
823 <td>
824 &commat;array
825 </td>
826 <td>
827 &commat;typedArray
828 </td>
829 </tr>
830
831 <tr>
832 <td>
833 Animator
834 </td>
835 <td>
836 &commat;animator
837 </td>
838 <td>
839 &commat;animator
840 </td>
841 </tr>
842
843 <tr>
844 <td>
845 StateListAnimator
846 </td>
847 <td>
848 &commat;animator
849 </td>
850 <td>
851 &commat;stateListAnimator
852 </td>
853 </tr>
854
855 <tr>
856 <td>
857 color <code>int</code>
858 </td>
859 <td>
860 <pre>
861&commat;color
862</pre>
863 </td>
864 <td>
865 &commat;color
866 </td>
867 </tr>
868
869 <tr>
870 <td>
871 ColorStateList
872 </td>
873 <td>
874 &commat;color
875 </td>
876 <td>
877 &commat;colorStateList
878 </td>
879 </tr>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700880</table>
881
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700882<h2 id="data_objects">
883 Data Objects
884</h2>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700885
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700886<p>
887 Any plain old Java object (POJO) may be used for data binding, but modifying
888 a POJO will not cause the UI to update. The real power of data binding can be
889 used by giving your data objects the ability to notify when data changes.
890 There are three different data change notification mechanisms,
891 <code>Observable</code> objects, <code>ObservableField</code>s, and
892 <code>observable collections</code>.
893</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700894
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700895<p>
896 When one of these observable data object is bound to the UI and a property of
897 the data object changes, the UI will be updated automatically.
898</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700899
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700900<h3 id="observable_objects">
901 Observable Objects
902</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700903
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700904<p>
905 A class implementing <code>android.databinding.Observable</code> interface
906 will allow the binding to attach a single listener to a bound object to
907 listen for changes of all properties on that object.
908</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700909
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700910<p>
911 The <code>Observable</code> interface has a mechanism to add and remove
912 listeners, but notifying is up to the developer. To make development easier,
913 a base class, <code>BaseObservable,</code> was created to implement the
914 listener registration mechanism. The data class implementer is still
915 responsible for notifying when the properties change. This is done by
916 assigning a <code>Bindable</code> annotation to the getter and notifying in
917 the setter.
918</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700919
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700920<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700921<strong>private static class </strong>User <strong>extends </strong>BaseObservable {
922 <strong>private </strong>String <strong>firstName</strong>;
923 <strong>private </strong>String <strong>lastName</strong>;
924 &commat;Bindable
925 <strong>public </strong>String getFirstName() {
926 <strong>return this</strong>.<strong>firstName</strong>;
927 }
928 &commat;Bindable
929 <strong>public </strong>String getFirstName() {
930 <strong>return this</strong>.<strong>lastName</strong>;
931 }
932 <strong>public void </strong>setFirstName(String firstName) {
933 <strong>this</strong>.<strong>firstName </strong>= firstName;
934 notifyPropertyChanged(BR.firstName);
935 }
936 <strong>public void </strong>setLastName(String lastName) {
937 <strong>this</strong>.<strong>lastName </strong>= lastName;
938 notifyPropertyChanged(BR.lastName);
939 }
940}
941</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700942<p>
943 The <code>Bindable</code> annotation generates an entry in the BR class file
944 during compilation. The BR class file will be generated in the module
945 package.If the base class for data classes cannot be changed, the
946 <code>Observable</code> interface may be implemented using the convenient
947 <code>PropertyChangeRegistry</code> to store and notify listeners
948 efficiently.
949</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700950
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700951<h3 id="observablefields">
952 ObservableFields
953</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700954
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700955<p>
956 A little work is involved in creating Observable classes, so developers who
957 want to save time or have few properties may use ObservableFields.
958 ObservableFields are self-contained observable objects that have a single
959 field. There are versions for all primitive types and one for reference
960 types. To use, create a public final field in the data class:
961</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700962
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700963<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700964<strong>private static class </strong>User <strong>extends </strong>BaseObservable {
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700965 <strong>public final </strong>ObservableField&lt;String&gt; <strong>firstName </strong>=
966 <strong>new </strong>ObservableField&lt;&gt;();
967 <strong>public final </strong>ObservableField&lt;String&gt; <strong>lastName </strong>=
968 <strong>new </strong>ObservableField&lt;&gt;();
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700969 <strong>public final </strong>ObservableInt <strong>age </strong>= <strong>new </strong>ObservableInt();
970}
971</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700972<p>
973 That&apos;s it! To access the value, use the set and get accessor methods:
974</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700975
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700976<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700977user.<strong>firstName</strong>.set(<strong>"Google"</strong>);
978<strong>int </strong>age = user.<strong>age</strong>.get();
979</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700980<h3 id="observable_collections">
981 Observable Collections
982</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700983
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700984<p>
985 Some applications use more dynamic structures to hold data. Observable
986 collections allow keyed access to these data objects.ObservableArrayMap is
987 useful when the key is a reference type, such as String.
988</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700989
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700990<pre>
991ObservableArrayMap&lt;String, Object&gt; user = <strong>new </strong>ObservableArrayMap&lt;&gt;();
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700992user.put(<strong>"firstName"</strong>, <strong>"Google"</strong>);
993user.put(<strong>"lastName"</strong>, <strong>"Inc."</strong>);
994user.put(<strong>"age"</strong>, 17);
995</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -0700996<p>
997 In the layout, the map may be accessed through the String keys:
998</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -0700999
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001000<pre>
1001&lt;<strong>data</strong>&gt;
1002 &lt;<strong>import type="android.databinding.ObservableMap"</strong>/&gt;
1003 &lt;<strong>variable name="user" type="ObservableMap&amp;lt;String, Object&gt;"</strong>/&gt;
1004&lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001005
1006&lt;<strong>TextView
1007 android:text=&apos;&commat;{user["lastName"]}&apos;
1008 android:layout_width="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001009 android:layout_height="wrap_content"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001010&lt;<strong>TextView
1011 android:text=&apos;&commat;{String.valueOf(1 + (Integer)user["age"])}&apos;
1012 android:layout_width="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001013 android:layout_height="wrap_content"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001014</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001015<p>
1016 ObservableArrayList is useful when the key is an integer:
1017</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001018
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001019<pre>
1020ObservableArrayList&lt;Object&gt; user = <strong>new </strong>ObservableArrayList&lt;&gt;();
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001021user.add(<strong>"Google"</strong>);
1022user.add(<strong>"Inc."</strong>);
1023user.add(17);
1024</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001025<p>
1026 In the layout, the list may be accessed through the indices:
1027</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001028
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001029<pre>
1030&lt;<strong>data</strong>&gt;
1031 &lt;<strong>import type="android.databinding.ObservableList"</strong>/&gt;
1032 &lt;<strong>import type="com.example.my.app.Fields"</strong>/&gt;
1033 &lt;<strong>variable name="user" type="ObservableList&amp;lt;Object&gt;"</strong>/&gt;
1034&lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001035
1036&lt;<strong>TextView
1037 android:text=&apos;&commat;{user[Fields.LAST_NAME]}&apos;
1038 android:layout_width="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001039 android:layout_height="wrap_content"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001040&lt;<strong>TextView
1041 android:text=&apos;&commat;{String.valueOf(1 + (Integer)user[Fields.AGE])}&apos;
1042 android:layout_width="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001043 android:layout_height="wrap_content"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001044</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001045<h2 id="generated_binding">
1046 Generated Binding
1047</h2>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001048
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001049<p>
1050 The generated binding class links the layout variables with the Views within
1051 the layout. As discussed earlier, the name and package of the Binding may be
1052 <a href="#custom_binding_class_names">customized</a>. The Generated binding
1053 classes all extend <code>android.databinding.ViewDataBinding</code>.
1054</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001055
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001056<h3 id="creating">
1057 Creating
1058</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001059
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001060<p>
1061 The binding should be created soon after inflation to ensure that the View
1062 hierarchy is not disturbed prior to binding to the Views with expressions
1063 within the layout. There are a few ways to bind to a layout. The most common
1064 is to use the static methods on the Binding class.The inflate method inflates
1065 the View hierarchy and binds to it all it one step. There is a simpler
1066 version that only takes a <code>LayoutInflater</code> and one that takes a
1067 <code>ViewGroup</code> as well:
1068</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001069
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001070<pre>
1071MyLayoutBinding binding = MyLayoutBinding.<em>inflate</em>(<strong>layoutInflater</strong>);
1072MyLayoutBinding binding = MyLayoutBinding.<em>inflate</em>(LayoutInflater, viewGroup, false);
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001073</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001074<p>
1075 If the layout was inflated using a different mechanism, it may be bound
1076 separately:
1077</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001078
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001079<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001080MyLayoutBinding binding = MyLayoutBinding.<em>bind</em>(viewRoot);
1081</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001082<p>
1083 Sometimes the binding cannot be known in advance. In such cases, the binding
1084 can be created using the DataBindingUtil class:
1085</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001086
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001087<pre>
1088ViewDataBinding binding = DataBindingUtil.<em>inflate</em>(LayoutInflater, layoutId,
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001089 parent, attachToParent);
1090ViewDataBinding binding = DataBindingUtil.<em>bindTo</em>(viewRoot, layoutId);
1091</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001092<h3 id="views_with_ids">
1093 Views With IDs
1094</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001095
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001096<p>
1097 A public final field will be generated for each View with an ID in the
1098 layout. The binding does a single pass on the View hierarchy, extracting the
1099 Views with IDs. This mechanism can be faster than calling findViewById for
1100 several Views. For example:
1101</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001102
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001103<pre>
1104&lt;<strong>layout xmlns:android="http://schemas.android.com/apk/res/android"</strong>&gt;
1105 &lt;<strong>data</strong>&gt;
1106 &lt;<strong>variable name="user" type="com.example.User"</strong>/&gt;
1107 &lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001108 &lt;<strong>LinearLayout
1109 android:orientation="vertical"
1110 android:layout_width="match_parent"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001111 android:layout_height="match_parent"</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001112 &lt;<strong>TextView android:layout_width="wrap_content"
1113 android:layout_height="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001114 android:text="&commat;{user.firstName}"</strong>
1115 <strong>android:id="&commat;+id/firstName"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001116 &lt;<strong>TextView android:layout_width="wrap_content"
1117 android:layout_height="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001118 android:text="&commat;{user.lastName}"</strong>
1119 <strong>android:id="&commat;+id/lastName"</strong>/&gt;
1120 &lt;/<strong>LinearLayout</strong>&gt;
1121&lt;/<strong>layout</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001122</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001123<p>
1124 Will generate a binding class with:
1125</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001126
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001127<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001128<strong>public final </strong>TextView <strong>firstName</strong>;
1129<strong>public final </strong>TextView <strong>lastName</strong>;
1130</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001131<p>
1132 IDs are not nearly as necessary as without data binding, but there are still
1133 some instances where access to Views are still necessary from code.
1134</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001135
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001136<h3 id="variables2">
1137 Variables
1138</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001139
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001140<p>
1141 Each variable will be given accessor methods.
1142</p>
1143
1144<pre>
1145&lt;<strong>data</strong>&gt;
1146 &lt;<strong>import type="android.graphics.drawable.Drawable"</strong>/&gt;
1147 &lt;<strong>variable name="user" type="com.example.User"</strong>/&gt;
1148 &lt;<strong>variable name="image" type="Drawable"</strong>/&gt;
1149 &lt;<strong>variable name="note" type="String"</strong>/&gt;
1150&lt;/<strong>data</strong>&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001151</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001152<p>
1153 will generate setters and getters in the binding:
1154</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001155
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001156<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001157<strong>public abstract </strong>com.example.User getUser();
1158<strong>public abstract void </strong>setUser(com.example.User user);
1159<strong>public abstract </strong>Drawable getImage();
1160<strong>public abstract void </strong>setImage(Drawable image);
1161<strong>public abstract </strong>String getNote();
1162<strong>public abstract void </strong>setNote(String note);
1163</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001164<h3 id="viewstubs">
1165 ViewStubs
1166</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001167
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001168<p>
1169 ViewStubs are a little different from normal Views. They start off invisible
1170 and when they either are made visible or are explicitly told to inflate, they
1171 replace themselves in the layout by inflating another layout.
1172</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001173
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001174<p>
1175 Because the ViewStub essentially disappears from the View hierarchy, the View
1176 in the binding object must also disappear to allow collection. Because the
1177 Views are final, a ViewStubProxy object takes the place of the ViewStub,
1178 giving the developer access to the ViewStub when it exists and also access to
1179 the inflated View hierarchy when the ViewStub has been inflated.
1180</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001181
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001182<p>
1183 When inflating another layout, a binding must be established for the new
1184 layout. Therefore, the ViewStubProxy must listen to the ViewStub&apos;s
1185 OnInflateListener and establish the binding at that time. Since only one can
1186 exist, the ViewStubProxy allows the developer to set an OnInflateListener on
1187 it that it will call after establishing the binding.
1188</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001189
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001190<h3 id="advanced_binding">
1191 Advanced Binding
1192</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001193
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001194<h4 id="dynamic_variables">
1195 Dynamic Variables
1196</h4>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001197
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001198<p>
1199 At times, the specific binding class won&apos;t be known. For example, a
1200 RecyclerView Adapter operating against arbitrary layouts won&apos;t know the
1201 specific binding class. It still must assign the binding value during the
1202 onBindViewHolder.
1203</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001204
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001205<p>
1206 In this example, all layouts that the RecyclerView binds to have an "item"
1207 variable. The BindingHolder has a getBinding method returning the
1208 <code>ViewDataBinding</code> base.
1209</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001210
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001211<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001212<strong>public void </strong>onBindViewHolder(BindingHolder holder, <strong>int </strong>position) {
1213 <strong>final </strong>T item = <strong>mItems</strong>.get(position);
1214 holder.getBinding().setVariable(BR.item, item);
1215 holder.getBinding().executePendingBindings();
1216}
1217</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001218<h4 id="immediate_binding">
1219 Immediate Binding
1220</h4>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001221
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001222<p>
1223 When a variable or observable changes, the binding will be scheduled to
1224 change before the next frame. There are times, however, when binding must be
1225 executed immediately. To force execution, use the
1226 <code>executePendingBindings()</code> method.
1227</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001228
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001229<h4>
1230 Background Thread
1231</h4>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001232
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001233<p>
1234 You can change your data model in a background thread as long as it is not a
1235 collection. Data binding will localize each variable / field while evaluating
1236 to avoid any concurrency issues.
1237</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001238
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001239<h2 id="attribute_setters">
1240 Attribute Setters
1241</h2>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001242
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001243<p>
1244 Whenever a bound value changes, the generated binding class must call a
1245 setter method on the View with the binding expression. The data binding
1246 framework has ways to customize which method to call to set the value.
1247</p>
1248
1249<h3 id="automatic_setters">
1250 Automatic Setters
1251</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001252For an attribute, data binding tries to find the method setAttribute. The
1253namespace for the attribute does not matter, only the attribute name itself.
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001254<p>
1255 For example, an expression associated with TextView&apos;s attribute
1256 <strong><code>android:text</code></strong> will look for a setText(String).
1257 If the expression returns an int, data binding will search for a setText(int)
1258 method. Be careful to have the expression return the correct type, casting if
1259 necessary. Note that data binding will work even if no attribute exists with
1260 the given name. You can then easily "create" attributes for any setter by
1261 using data binding. For example, support DrawerLayout doesn&apos;t have any
1262 attributes, but plenty of setters. You can use the automatic setters to use
1263 one of these.
1264</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001265
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001266<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001267&lt;android.support.v4.widget.<strong>DrawerLayout
1268 android:layout_width="wrap_content"
1269 android:layout_height="wrap_content"
1270 app:scrimColor="&commat;{&commat;color/scrim}"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001271 app:drawerListener="&commat;{fragment.drawerListener}"/&gt;</strong>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001272</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001273<h3 id="renamed_setters">
1274 Renamed Setters
1275</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001276
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001277<p>
1278 Some attributes have setters that don&apos;t match by name. For these
1279 methods, an attribute may be associated with the setter through
1280 BindingMethods annotation. This must be associated with a class and contains
1281 BindingMethod annotations, one for each renamed method. For example, the
1282 <strong><code>android:tint</code></strong> attribute is really associated
1283 with setImageTintList, not setTint.
1284</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001285
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001286<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001287&commat;BindingMethods({
1288 &commat;BindingMethod(type = <strong>"android.widget.ImageView"</strong>,
1289 attribute = <strong>"android:tint"</strong>,
1290 method = <strong>"setImageTintList"</strong>),
1291})
1292</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001293<p>
1294 It is unlikely that developers will need to rename setters; the android
1295 framework attributes have already been implemented.
1296</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001297
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001298<h3 id="custom_setters">
1299 Custom Setters
1300</h3>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001301
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001302<p>
1303 Some attributes need custom binding logic. For example, there is no
1304 associated setter for the <strong><code>android:paddingLeft</code></strong>
1305 attribute. Instead, <code>setPadding(left, top, right, bottom)</code> exists.
1306 A static binding adapter method with the <code>BindingAdapter</code>
1307 annotation allows the developer to customize how a setter for an attribute is
1308 called.
1309</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001310
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001311<p>
1312 The android attributes have already had <code>BindingAdapter</code>s created.
1313 For example, here is the one for <code>paddingLeft</code>:
1314</p>
1315
1316<pre>
1317
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001318&commat;BindingAdapter(<strong>"android:paddingLeft"</strong>)
1319<strong>public static void </strong>setPaddingLeft(View view, <strong>int </strong>padding) {
1320 view.setPadding(padding,
1321 view.getPaddingTop(),
1322 view.getPaddingRight(),
1323 view.getPaddingBottom());
1324}
1325</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001326<p>
1327 Binding adapters are useful for other types of customization. For example, a
1328 custom loader can be called off-thread to load an image.
1329</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001330
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001331<p>
1332 Developer-created binding adapters will override the data binding default
1333 adapters when there is a conflict.
1334</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001335
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001336<p>
1337 You can also have adapters that receive multiple parameters.
1338</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001339
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001340<pre>
1341&commat;BindingAdapter({<strong>"bind:imageUrl"</strong>, <strong>"bind:error"</strong>})
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001342<strong>public static void </strong>loadImage(ImageView view, String url, Drawable error) {
1343 Picasso.<em>with</em>(view.getContext()).load(url).error(error).into(view);
1344}
1345</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001346<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001347&lt;ImageView app:imageUrl=“&commat;{venue.imageUrl}”
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001348app:error=“&commat;{&commat;drawable/venueError}”/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001349</pre>
1350
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001351<p>
1352 This adapter will be called if both <strong>imageUrl</strong> and
1353 <strong>error</strong> are used for an ImageView and <em>imageUrl</em> is a
1354 string and <em>error</em> is a drawable.
1355</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001356
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001357<ul>
1358 <li>Custom namespaces are ignored during matching.
1359 </li>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001360
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001361 <li>You can also write adapters for android namespace.
1362 </li>
1363</ul>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001364
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001365<h2 id="converters">
1366 Converters
1367</h2>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001368
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001369<h3 id="object_conversions">
1370 Object Conversions
1371</h3>
1372
1373<p>
1374 When an Object is returned from a binding expression, a setter will be chosen
1375 from the automatic, renamed, and custom setters. The Object will be cast to a
1376 parameter type of the chosen setter.
1377</p>
1378
1379<p>
1380 This is a convenience for those using ObservableMaps to hold data. for
1381 example:
1382</p>
1383
1384<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001385&lt;<strong>TextView
1386 android:text=&apos;&commat;{userMap["lastName"]}&apos;
1387 android:layout_width="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001388 android:layout_height="wrap_content"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001389</pre>
1390
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001391<p>
1392The <code>userMap</code> returns an Object and that Object will be automatically cast to
1393 parameter type found in the setter <code>setText(CharSequence)</code>. When there
1394 may be confusion about the parameter type, the developer will need
1395 to cast in the expression.
1396</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001397
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001398<h3 id="custom_conversions">Custom Conversions</h3>
1399
1400<p>
1401 Sometimes conversions should be automatic between specific types. For
1402 example, when setting the background:
1403</p>
1404
1405<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001406&lt;<strong>View
1407 android:background="&commat;{isError ? &commat;color/red : &commat;color/white}"
1408 android:layout_width="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001409 android:layout_height="wrap_content"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001410</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001411<p>
1412 Here, the background takes a <code>Drawable</code>, but the color is an
1413 integer. Whenever a <code>Drawable</code> is expected and an integer is
1414 returned, the <code>int</code> should be converted to a
1415 <code>ColorDrawable</code>. This conversion is done using a static method
1416 with a BindingConversion annotation:
1417</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001418
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001419<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001420&commat;BindingConversion
1421<strong>public static </strong>ColorDrawable convertColorToDrawable(<strong>int </strong>color) {
1422 <strong>return new </strong>ColorDrawable(color);
1423}
1424</pre>
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001425<p>
1426 Note that conversions only happen at the setter level, so it is <strong>not
1427 allowed</strong> to mix types like this:
1428</p>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001429
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001430<pre>
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001431&lt;<strong>View
1432 android:background="&commat;{isError ? &commat;drawable/error : &commat;color/white}"
1433 android:layout_width="wrap_content"
Dirk Doughertyea1f6fb2015-05-26 20:31:12 -07001434 android:layout_height="wrap_content"</strong>/&gt;
Dirk Dougherty493ff3c2015-05-26 16:52:23 -07001435</pre>