1page.title=Data Binding Guide 2page.tags="databinding", "layouts" 3@jd:body 4 5<div id="qv-wrapper"> 6 <div id="qv"> 7 <h2> 8 In this document: 9 </h2> 10 11 <ol> 12 <li> 13 <a href="#build_environment">Build Environment</a> 14 </li> 15 16 <li> 17 <a href="#data_binding_layout_files">Data Binding Layout Files</a> 18 <ol> 19 <li> 20 <a href="#writing_expressions">Writing your first data binding 21 expressions</a> 22 </li> 23 24 <li> 25 <a href="#data_object">Data Object</a> 26 </li> 27 28 <li> 29 <a href="#binding_data">Binding Data</a> 30 </li> 31 32 <li> 33 <a href="#binding_events">Binding Events</a> 34 </li> 35 </ol> 36 </li> 37 38 <li> 39 <a href="#layout_details">Layout Details</a> 40 <ol> 41 <li> 42 <a href="#imports">Imports</a> 43 </li> 44 45 <li> 46 <a href="#variables">Variables</a> 47 </li> 48 49 <li> 50 <a href="#custom_binding_class_names">Custom Binding Class Names</a> 51 </li> 52 53 <li> 54 <a href="#includes">Includes</a> 55 </li> 56 57 <li> 58 <a href="#expression_language">Expression Language</a> 59 </li> 60 </ol> 61 </li> 62 63 <li> 64 <a href="#data_objects">Data Objects</a> 65 <ol> 66 <li> 67 <a href="#observable_objects">Observable Objects</a> 68 </li> 69 70 <li> 71 <a href="#observablefields">ObservableFields</a> 72 </li> 73 74 <li> 75 <a href="#observable_collections">Observable Collections</a> 76 </li> 77 </ol> 78 </li> 79 80 <li> 81 <a href="#generated_binding">Generated Binding</a> 82 <ol> 83 <li> 84 <a href="#creating">Creating</a> 85 </li> 86 87 <li> 88 <a href="#views_with_ids">Views With IDs</a> 89 </li> 90 91 <li> 92 <a href="#variables">Variables</a> 93 </li> 94 95 <li> 96 <a href="#viewstubs">ViewStubs</a> 97 </li> 98 99 <li> 100 <a href="#advanced_binding">Advanced Binding</a> 101 </li> 102 </ol> 103 </li> 104 105 <li> 106 <a href="#attribute_setters">Attribute Setters</a> 107 <ol> 108 <li> 109 <a href="#automatic_setters">Automatic Setters</a> 110 </li> 111 112 <li> 113 <a href="#renamed_setters">Renamed Setters</a> 114 </li> 115 116 <li> 117 <a href="#custom_setters">Custom Setters</a> 118 </li> 119 </ol> 120 </li> 121 122 <li> 123 <a href="#converters">Converters</a> 124 <ol> 125 <li> 126 <a href="#object_conversions">Object Conversions</a> 127 </li> 128 129 <li> 130 <a href="#custom_conversions">Custom Conversions</a> 131 </li> 132 </ol> 133 </li> 134 </ol> 135 </div><!-- qv --> 136</div><!-- qv-wrapper --> 137 138<p> 139 This document explains how to use the Data Binding Library to write 140 declarative layouts and minimize the glue code necessary to bind your 141 application logic and layouts. 142</p> 143 144<p>The Data Binding Library offers both flexibility and broad comnpatibility 145— it's a support library, so you can use it with all Android platform 146versions back to <strong>Android 2.1</strong> (API level 7+).</p> 147 148<p>To use data binding, Android Plugin for Gradle <strong>1.3.0-beta4</strong> 149or higher is required.</p> 150 151<h4>Beta release</h4> 152 153<div class="caution"> 154 <p>Please note that the Data Binding library is a <strong>beta release</strong>. 155 While Data Binding is in beta, developers should be aware of the following 156 caveats:</p> 157 <ul> 158 <li> 159 This is a beta release of the feature intended to generate developer 160 feedback. It might contain bugs, and it might not work for your use case, 161 so use it at your own risk. That said, we do want your feedback! Please 162 let us know what is or isn’t working for you using the <a 163 href="https://code.google.com/p/android-developer-preview/">issue 164 tracker</a>. 165 </li> 166 <li> 167 The Data Binding library beta release is subject to significant changes, 168 including those which are not source code compatible with your app. That is, 169 significant rework may be required to take updates to the library in the future. 170 </li> 171 <li> 172 Developers should feel free to publish apps built with the Data Binding 173 library beta release, with the caveats that the standard Android SDK and 174 Google Play terms of service apply, and it’s always a great idea to test your 175 app thoroughly when adopting new libraries or tools. 176 </li> 177 <li> 178 We’re just getting started with Android Studio support at this time. 179 Further Android Studio support will come in the future. 180 </li> 181 <li> 182 By using the Data Binding library beta release, you acknowledge these 183 caveats.</li> 184 </ul> 185</div> 186 187<h2 id="build_environment"> 188 Build Environment 189</h2> 190 191<p>To get started with Data Binding, download the library from the Support 192repository in the Android SDK manager. </p> 193 194<p>The Data Binding plugin requires Android Plugin for Gradle <strong>1.3.0-beta4 195or higher</strong>, so update your build dependencies (in the top-level 196<code>build.gradle</code> file) as needed.</p> 197 198<p>Also, make sure you are using a compatible version of Android Studio. 199<strong>Android Studio 1.3</strong> adds the code-completion and layout-preview 200support for data binding.</p> 201 202<p> 203 <strong>Setting Up Work Environment:</strong> 204</p> 205 206<p> 207 To set up your application to use data binding, add data binding to the class 208 path of your top-level <code>build.gradle</code> file, right below "android". 209</p> 210 211<pre> 212 dependencies { 213 classpath <strong>"com.android.tools.build:gradle:1.3.0-beta4"</strong> 214 classpath <strong>"com.android.databinding:dataBinder:1.0-rc1"</strong> 215 } 216</pre> 217<p> 218 Then make sure jcenter is in the repositories list for your projects in the top-level 219 <code>build.gradle</code> file. 220</p> 221 222<pre> 223allprojects { 224 repositories { 225 jcenter() 226 } 227} 228</pre> 229<p> 230 In each module you want to use data binding, apply the plugin right after 231 android plugin 232</p> 233 234<pre> 235apply plugin: 'com.android.application' 236apply plugin: 'com.android.databinding' 237</pre> 238<p> 239 The data binding plugin is going to add necessary <strong>provided</strong> 240 and <strong>compile configuration</strong> dependencies to your project. 241</p> 242 243<h2 id="data_binding_layout_files"> 244 Data Binding Layout Files 245</h2> 246 247<h3 id="writing_expressions"> 248 Writing your first data binding expressions 249</h3> 250 251<p> 252 Data-binding layout files are slightly different and start with a root tag of 253 <strong>layout</strong> followed by a <strong>data</strong> element and a 254 <strong>view</strong> root element. This view element is what your root would 255 be in a non-binding layout file. A sample file looks like this: 256</p> 257 258<pre> 259<?xml version="1.0" encoding="utf-8"?> 260<layout xmlns:android="http://schemas.android.com/apk/res/android"> 261 <data> 262 <variable name="user" type="com.example.User"/> 263 </data> 264 <LinearLayout 265 android:orientation="vertical" 266 android:layout_width="match_parent" 267 android:layout_height="match_parent"> 268 <TextView android:layout_width="wrap_content" 269 android:layout_height="wrap_content" 270 android:text="@{user.firstName}"/> 271 <TextView android:layout_width="wrap_content" 272 android:layout_height="wrap_content" 273 android:text="@{user.lastName}"/> 274 </LinearLayout> 275</layout> 276</pre> 277<p> 278 The user <strong>variable</strong> within <strong>data</strong> describes a 279 property that may be used within this layout. 280</p> 281 282<pre> 283<<strong>variable name="user" type="com.example.User"</strong>/> 284</pre> 285<p> 286 Expressions within the layout are written in the attribute properties using 287 the “<code>@{}</code>” syntax. Here, the TextView’s text is set to the 288 firstName property of user: 289</p> 290 291<pre> 292<TextView android:layout_width="wrap_content" 293 android:layout_height="wrap_content" 294 android:text="@{user.firstName}"/> 295</pre> 296<h3 id="data_object"> 297 Data Object 298</h3> 299 300<p> 301 Let’s assume for now that you have a plain-old Java object (POJO) for User: 302</p> 303 304<pre> 305public class User { 306 public final String firstName; 307 public final String lastName; 308 public User(String firstName, String lastName) { 309 this.firstName = firstName; 310 this.lastName = lastName; 311 } 312} 313</pre> 314<p> 315 This type of object has data that never changes. It is common in applications 316 to have data that is read once and never changes thereafter. It is also 317 possible to use a JavaBeans objects: 318</p> 319 320<pre> 321public class User { 322 private final String firstName; 323 private final String lastName; 324 public User(String firstName, String lastName) { 325 this.firstName = firstName; 326 this.lastName = lastName; 327 } 328 public String getFirstName() { 329 return this.firstName; 330 } 331 public String getLastName() { 332 return this.lastName; 333 } 334} 335</pre> 336<p> 337 From the perspective of data binding, these two classes are equivalent. The 338 expression <strong><code>@{user.firstName}</code></strong> used for 339 the TextView’s <strong><code>android:text</code></strong> attribute will 340 access the <strong><code>firstName</code></strong> field in the former class 341 and the <code>getFirstName()</code> method in the latter class. Alternatively, it 342 will also be resolved to <code>firstName()</code> if that method exists. 343</p> 344 345<h3 id="binding_data"> 346 Binding Data 347</h3> 348 349<p> 350 By default, a Binding class will be generated based on the name of the layout 351 file, converting it to Pascal case and suffixing “Binding” to it. The above 352 layout file was <code>main_activity.xml</code> so the generate class was 353 <code>MainActivityBinding</code>. This class holds all the bindings from the 354 layout properties (e.g. the <code>user</code> variable) to the layout’s Views 355 and knows how to assign values for the binding expressions.The easiest means 356 for creating the bindings is to do it while inflating: 357</p> 358 359<pre> 360@Override 361protected void onCreate(Bundle savedInstanceState) { 362 super.onCreate(savedInstanceState); 363 MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity); 364 User user = new User("Test", "User"); 365 binding.setUser(user); 366} 367</pre> 368<p> 369 You’re done! Run the application and you’ll see Test User in the UI. 370 Alternatively, you can get the view via: 371</p> 372 373<pre> 374MainActivityBinding binding = MainActivityBinding.<em>inflate</em>(getLayoutInflater()); 375</pre> 376<p> 377 If you are using data binding items inside a ListView or RecyclerView 378 adapter, you may prefer to use: 379</p> 380 381<pre> 382ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false); 383//or 384ListItemBinding binding = DataBindingUtil.<em>inflate</em>(layoutInflater, R.layout.<em><strong>list_item</strong></em>, viewGroup, <strong>false</strong>); 385</pre> 386 387<h3 id="binding_events"> 388 Binding Events 389</h3> 390<p> 391 Events may be bound to handler methods directly, similar to the way 392 <strong><code>android:onClick</code></strong> can be assigned to a method in the Activity. 393 Event attribute names are governed by the name of the listener method with a few exceptions. 394 For example, {@link android.view.View.OnLongClickListener} has a method {@link android.view.View.OnLongClickListener#onLongClick onLongClick()}, 395 so the attribute for this event is <code>android:onLongClick</code>. 396</p> 397<p> 398 To assign an event to its handler, use a normal binding expression, with the value 399 being the method name to call. For example, if your data object has two methods: 400</p> 401<pre>public class MyHandlers { 402 public void onClickFriend(View view) { ... } 403 public void onClickEnemy(View view) { ... } 404} 405</pre> 406<p> 407 The binding expression can assign the click listener for a View: 408</p> 409<pre> 410<?xml version="1.0" encoding="utf-8"?> 411<layout xmlns:android="http://schemas.android.com/apk/res/android"> 412 <data> 413 <variable name="handlers" type="com.example.Handlers"/> 414 <variable name="user" type="com.example.User"/> 415 </data> 416 <LinearLayout 417 android:orientation="vertical" 418 android:layout_width="match_parent" 419 android:layout_height="match_parent"> 420 <TextView android:layout_width="wrap_content" 421 android:layout_height="wrap_content" 422 android:text="@{user.firstName}" 423 android:onClick="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/> 424 <TextView android:layout_width="wrap_content" 425 android:layout_height="wrap_content" 426 android:text="@{user.lastName}" 427 android:onClick="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/> 428 </LinearLayout> 429</layout> 430</pre> 431<h2 id="layout_details"> 432 Layout Details 433</h2> 434 435<h3 id="imports"> 436 Imports 437</h3> 438 439<p> 440 Zero or more <strong><code>import</code></strong> elements may be used inside 441 the <strong><code>data</code></strong> element. These allow easy reference to 442 classes inside your layout file, just like in Java. 443</p> 444 445<pre> 446<data> 447 <import type="android.view.View"/> 448</data> 449</pre> 450<p> 451 Now, View may be used within your binding expression: 452</p> 453 454<pre> 455<TextView 456 android:text="@{user.lastName}" 457 android:layout_width="wrap_content" 458 android:layout_height="wrap_content" 459 android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/> 460</pre> 461<p> 462 When there are class name conflicts, one of the classes may be renamed to an 463 “alias:” 464</p> 465 466<pre> 467<import type="android.view.View"/> 468<import type="com.example.real.estate.View" 469 alias="Vista"/> 470</pre> 471<p> 472 Now, <strong><code>Vista</code></strong> may be used to reference the 473 <code>com.example.real.estate.View</code> and 474 <strong><code>View</code></strong> may be used to reference 475 <code>android.view.View</code> within the layout file. Imported types may be 476 used as type references in variables and expressions: 477</p> 478 479<pre> 480<data> 481 <import type="com.example.User"/> 482 <import type="java.util.List"/> 483 <variable name="user" type="User"/> 484 <variable name="userList" type="List&lt;User>"/> 485</data> 486</pre> 487<p class="caution"> 488 <strong>Note</strong>: Android Studio does not yet handle imports so the 489 autocomplete for imported variables may not work in your IDE. Your 490 application will still compile fine and you can work around the IDE issue by 491 using fully qualified names in your variable definitions. 492</p> 493 494<pre> 495<TextView 496 android:text="@{((User)(user.connection)).lastName}" 497 android:layout_width="wrap_content" 498 android:layout_height="wrap_content"/> 499</pre> 500<p> 501 Imported types may also be used when referencing static fields and methods in 502 expressions: 503</p> 504 505<pre> 506<data> 507 <import type="com.example.MyStringUtils"/> 508 <variable name="user" type="com.example.User"/> 509</data> 510… 511<TextView 512 android:text="@{MyStringUtils.capitalize(user.lastName)}" 513 android:layout_width="wrap_content" 514 android:layout_height="wrap_content"/> 515</pre> 516<p> 517 Just as in Java, <code>java.lang.*</code> is imported automatically. 518</p> 519 520<h3 id="variables"> 521 Variables 522</h3> 523 524<p> 525 Any number of <strong><code>variable</code></strong> elements may be used 526 inside the <strong><code>data</code></strong> element. Each 527 <strong><code>variable</code></strong> element describes a property that may 528 be set on the layout to be used in binding expressions within the layout 529 file. 530</p> 531 532<pre> 533<data> 534 <import type="android.graphics.drawable.Drawable"/> 535 <variable name="user" type="com.example.User"/> 536 <variable name="image" type="Drawable"/> 537 <variable name="note" type="String"/> 538</data> 539</pre> 540<p> 541 The variable types are inspected at compile time, so if a variable implements 542 {@link android.databinding.Observable} or is an <a href= 543 "#observable_collections">observable collection</a>, that should be reflected 544 in the type. If the variable is a base class or interface that does not 545 implement the Observable* interface, the variables will <strong>not 546 be</strong> observed! 547</p> 548 549<p> 550 When there are different layout files for various configurations (e.g. 551 landscape or portrait), the variables will be combined. There must not be 552 conflicting variable definitions between these layout files. 553</p> 554 555<p> 556 The generated binding class will have a setter and getter for each of the 557 described variables. The variables will take the default Java values until 558 the setter is called — <code>null</code> for reference types, 559 <code>0</code> for <code>int</code>, <code>false</code> for 560 <code>boolean</code>, etc. 561</p> 562 563<h3 id="custom_binding_class_names"> 564 Custom Binding Class Names 565</h3> 566 567<p> 568 By default, a Binding class is generated based on the name of the layout 569 file, starting it with upper-case, removing underscores ( _ ) and 570 capitalizing the following letter and then suffixing “Binding”. This class 571 will be placed in a databinding package under the module package. For 572 example, the layout file <code>contact_item.xml</code> will generate 573 <code>ContactItemBinding</code>. If the module package is 574 <code>com.example.my.app</code>, then it will be placed in 575 <code>com.example.my.app.databinding</code>. 576</p> 577 578<p> 579 Binding classes may be renamed or placed in different packages by adjusting 580 the <strong><code>class</code></strong> attribute of the 581 <strong><code>data</code></strong> element. For example: 582</p> 583 584<pre> 585<data class="ContactItem"> 586 ... 587</data> 588</pre> 589<p> 590 This generates the binding class as <code>ContactItem</code> in the 591 databinding package in the module package. If the class should be generated 592 in a different package within the module package, it may be prefixed with 593 “.”: 594</p> 595 596<pre> 597<data class=".ContactItem"> 598 ... 599</data> 600</pre> 601<p> 602 In this case, <code>ContactItem</code> is generated in the module package 603 directly. Any package may be used if the full package is provided: 604</p> 605 606<pre> 607<data class="com.example.ContactItem"> 608 ... 609</data> 610</pre> 611<h3 id="includes"> 612 Includes 613</h3> 614 615<p> 616 Variables may be passed into an included layout's binding from the 617 containing layout by using the application namespace and the variable name in 618 an attribute: 619</p> 620 621<pre> 622<?xml version="1.0" encoding="utf-8"?> 623<layout xmlns:android="http://schemas.android.com/apk/res/android" 624 xmlns:bind="http://schemas.android.com/apk/res-auto"> 625 <data> 626 <variable name="user" type="com.example.User"/> 627 </data> 628 <LinearLayout 629 android:orientation="vertical" 630 android:layout_width="match_parent" 631 android:layout_height="match_parent"> 632 <include layout="@layout/name" 633 bind:user="@{user}"/> 634 <include layout="@layout/contact" 635 bind:user="@{user}"/> 636 </LinearLayout> 637</layout> 638</pre> 639<p> 640 Here, there must be a <code>user</code> variable in both the 641 <code>name.xml</code> and <code>contact.xml</code> layout files. 642</p> 643<p> 644 Data binding does not support include as a direct child of a merge element. For example, 645 <strong>the following layout is not supported:</strong> 646</p> 647<pre> 648<?xml version="1.0" encoding="utf-8"?> 649<layout xmlns:android="http://schemas.android.com/apk/res/android" 650 xmlns:bind="http://schemas.android.com/apk/res-auto"> 651 <data> 652 <variable name="user" type="com.example.User"/> 653 </data> 654 <merge> 655 <include layout="@layout/name" 656 bind:user="@{user}"/> 657 <include layout="@layout/contact" 658 bind:user="@{user}"/> 659 </merge> 660</layout> 661</pre> 662<h3 id="expression_language"> 663 Expression Language 664</h3> 665 666<h4 id="common_features"> 667 Common Features 668</h4> 669 670<p> 671 The expression language looks a lot like a Java expression. These are the 672 same: 673</p> 674 675<ul> 676 <li>Mathematical <strong><code>+ - / * %</code></strong> 677 </li> 678 679 <li>String concatenation <strong><code>+</code></strong> 680 </li> 681 682 <li> 683 Logical <strong><code>&& ||</code></strong> 684 </li> 685 686 <li>Binary <strong><code>& | ^</code></strong> 687 </li> 688 689 <li>Unary <strong><code>+ - ! ~</code></strong> 690 </li> 691 692 <li>Shift <strong><code>>> >>> <<</code></strong> 693 </li> 694 695 <li>Comparison <strong><code>== > < >= <=</code></strong> 696 </li> 697 698 <li> 699 <strong><code>instanceof</code></strong> 700 </li> 701 702 <li>Grouping <strong><code>()</code></strong> 703 </li> 704 705 <li>Literals - character, String, numeric, <strong><code>null</code></strong> 706 </li> 707 708 <li>Cast 709 </li> 710 711 <li>Method calls 712 </li> 713 714 <li>Field access 715 </li> 716 717 <li>Array access <strong><code>[]</code></strong> 718 </li> 719 720 <li>Ternary operator <strong><code>?:</code></strong> 721 </li> 722</ul> 723 724<p> 725 Examples: 726</p> 727 728<pre> 729android:text="@{String.valueOf(index + 1)}" 730android:visibility="@{age &lt; 13 ? View.GONE : View.VISIBLE}" 731android:transitionName='@{"image_" + id}' 732</pre> 733<h4 id="missing_operations"> 734 Missing Operations 735</h4> 736 737<p> 738 A few operations are missing from the expression syntax that you can use in 739 Java. 740</p> 741 742<ul> 743 <li> 744 <strong><code>this</code></strong> 745 </li> 746 747 <li> 748 <strong><code>super</code></strong> 749 </li> 750 751 <li> 752 <strong><code>new</code></strong> 753 </li> 754 755 <li>Explicit generic invocation 756 </li> 757</ul> 758 759<h4 id="null_coalescing_operator"> 760 Null Coalescing Operator 761</h4> 762 763<p> 764 The null coalescing operator (<strong><code>??</code></strong>) chooses the 765 left operand if it is not null or the right if it is null. 766</p> 767 768<pre> 769<strong>android:text="@{user.displayName ?? user.lastName}"</strong> 770</pre> 771<p> 772 This is functionally equivalent to: 773</p> 774 775<pre> 776<strong>android:text="@{user.displayName != null ? user.displayName : user.lastName}"</strong> 777</pre> 778<h4 id="property_reference"> 779 Property Reference 780</h4> 781 782<p> 783 The first was already discussed in the <a href= 784 "#writing_your_first_data_binding_expressions">Writing your first data 785 binding expressions</a> above: short form JavaBean references. When an 786 expression references a property on a class, it uses the same format for 787 fields, getters, and ObservableFields. 788</p> 789 790<pre> 791<strong>android:text="@{user.lastName}"</strong> 792</pre> 793<h4> 794 Avoiding NullPointerException 795</h4> 796 797<p> 798 Generated data binding code automatically checks for nulls and avoid null 799 pointer exceptions. For example, in the expression 800 <code>@{user.name}</code>, if <code>user</code> is null, 801 <code>user.name</code> will be assigned its default value (null). If you were 802 referencing <code>user.age</code>, where age is an <code>int</code>, then it 803 would default to 0. 804</p> 805 806<h4 id="collections"> 807 Collections 808</h4> 809 810<p> 811 Common collections: arrays, lists, sparse lists, and maps, may be accessed 812 using the <code>[]</code> operator for convenience. 813</p> 814 815<pre> 816<data> 817 <import type="android.util.SparseArray"/> 818 <import type="java.util.Map"/> 819 <import type="java.util.List"/> 820 <variable name="list" type="List&lt;String>"/> 821 <variable name="sparse" type="SparseArray&lt;String>"/> 822 <variable name="map" type="Map&lt;String, String>"/> 823 <variable name="index" type="int"/> 824 <variable name="key" type="String"/> 825</data> 826… 827android:text="@{list[index]}" 828… 829android:text="@{sparse[index]}" 830… 831android:text="@{map[key]}" 832 833</pre> 834<h4 id="string_literals"> 835 String Literals 836</h4> 837 838<p> 839 When using single quotes around the attribute value, it is easy to use double 840 quotes in the expression: 841</p> 842 843<pre> 844android:text='@{map["firstName"]}' 845</pre> 846<p> 847 It is also possible to use double quotes to surround the attribute value. 848 When doing so, String literals should either use the &quot; or back quote 849 (`). 850</p> 851 852<pre> 853android:text="@{map[`firstName`}" 854android:text="@{map[&quot;firstName&quot;]}" 855</pre> 856<h4 id="resources"> 857 Resources 858</h4> 859 860<p> 861 It is possible to access resources as part of expressions using the normal 862 syntax: 863</p> 864 865<pre> 866android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}" 867</pre> 868<p> 869 Format strings and plurals may be evaluated by providing parameters: 870</p> 871 872<pre> 873android:text="@{@string/nameFormat(firstName, lastName)}" 874android:text="@{@plurals/banana(bananaCount)}" 875</pre> 876<p> 877 When a plural takes multiple parameters, all parameters should be passed: 878</p> 879 880<pre> 881 882 Have an orange 883 Have %d oranges 884 885android:text="@{@plurals/orange(orangeCount, orangeCount)}" 886</pre> 887<p> 888 Some resources require explicit type evaluation. 889</p> 890 891<table> 892 <tr> 893 <th> 894 Type 895 </th> 896 <th> 897 Normal Reference 898 </th> 899 <th> 900 Expression Reference 901 </th> 902 </tr> 903 904 <tr> 905 <td> 906 String[] 907 </td> 908 <td> 909 @array 910 </td> 911 <td> 912 @stringArray 913 </td> 914 </tr> 915 916 <tr> 917 <td> 918 int[] 919 </td> 920 <td> 921 @array 922 </td> 923 <td> 924 @intArray 925 </td> 926 </tr> 927 928 <tr> 929 <td> 930 TypedArray 931 </td> 932 <td> 933 @array 934 </td> 935 <td> 936 @typedArray 937 </td> 938 </tr> 939 940 <tr> 941 <td> 942 Animator 943 </td> 944 <td> 945 @animator 946 </td> 947 <td> 948 @animator 949 </td> 950 </tr> 951 952 <tr> 953 <td> 954 StateListAnimator 955 </td> 956 <td> 957 @animator 958 </td> 959 <td> 960 @stateListAnimator 961 </td> 962 </tr> 963 964 <tr> 965 <td> 966 color <code>int</code> 967 </td> 968 <td> 969 @color 970 </td> 971 <td> 972 @color 973 </td> 974 </tr> 975 976 <tr> 977 <td> 978 ColorStateList 979 </td> 980 <td> 981 @color 982 </td> 983 <td> 984 @colorStateList 985 </td> 986 </tr> 987</table> 988 989<h2 id="data_objects"> 990 Data Objects 991</h2> 992 993<p> 994 Any plain old Java object (POJO) may be used for data binding, but modifying 995 a POJO will not cause the UI to update. The real power of data binding can be 996 used by giving your data objects the ability to notify when data changes. 997 There are three different data change notification mechanisms, 998 <a href="#observable_objects">Observable objects</a>, 999 <a href="#observablefields">observable fields</a>, and 1000 <a href="#observable_collections">observable collection</a>s. 1001</p> 1002 1003<p> 1004 When one of these observable data object is bound to the UI and a property of 1005 the data object changes, the UI will be updated automatically. 1006</p> 1007 1008<h3 id="observable_objects"> 1009 Observable Objects 1010</h3> 1011 1012<p> 1013 A class implementing the {@link android.databinding.Observable} interface 1014 will allow the binding to attach a single listener to a bound object to 1015 listen for changes of all properties on that object. 1016</p> 1017 1018<p> 1019 The {@link android.databinding.Observable} interface has a mechanism to add and remove 1020 listeners, but notifying is up to the developer. To make development easier, 1021 a base class, {@link android.databinding.BaseObservable}, was created to implement the 1022 listener registration mechanism. The data class implementer is still 1023 responsible for notifying when the properties change. This is done by 1024 assigning a {@link android.databinding.Bindable} annotation to the getter and notifying in 1025 the setter. 1026</p> 1027 1028<pre> 1029private static class User extends BaseObservable { 1030 private String firstName; 1031 private String lastName; 1032 @Bindable 1033 public String getFirstName() { 1034 return this.firstName; 1035 } 1036 @Bindable 1037 public String getLastName() { 1038 return this.lastName; 1039 } 1040 public void setFirstName(String firstName) { 1041 this.firstName = firstName; 1042 notifyPropertyChanged(BR.firstName); 1043 } 1044 public void setLastName(String lastName) { 1045 this.lastName = lastName; 1046 notifyPropertyChanged(BR.lastName); 1047 } 1048} 1049</pre> 1050<p> 1051 The {@link android.databinding.Bindable} annotation generates an entry in the BR class file 1052 during compilation. The BR class file will be generated in the module 1053 package. If the base class for data classes cannot be changed, the 1054 {@link android.databinding.Observable} interface may be implemented using the convenient 1055 {@link android.databinding.PropertyChangeRegistry} to store and notify listeners 1056 efficiently. 1057</p> 1058 1059<h3 id="observablefields"> 1060 ObservableFields 1061</h3> 1062 1063<p> 1064 A little work is involved in creating {@link android.databinding.Observable} classes, so 1065 developers who want to save time or have few properties may use 1066 {@link android.databinding.ObservableField} and its siblings 1067 {@link android.databinding.ObservableBoolean}, 1068 {@link android.databinding.ObservableByte}, 1069 {@link android.databinding.ObservableChar}, 1070 {@link android.databinding.ObservableShort}, 1071 {@link android.databinding.ObservableInt}, 1072 {@link android.databinding.ObservableLong}, 1073 {@link android.databinding.ObservableFloat}, 1074 {@link android.databinding.ObservableDouble}, and 1075 {@link android.databinding.ObservableParcelable}. 1076 <code>ObservableFields</code> are self-contained observable objects that have a single 1077 field. The primitive versions avoid boxing and unboxing during access operations. 1078 To use, create a public final field in the data class: 1079</p> 1080 1081<pre> 1082private static class User { 1083 public final ObservableField<String> firstName = 1084 new ObservableField<>(); 1085 public final ObservableField<String> lastName = 1086 new ObservableField<>(); 1087 public final ObservableInt age = new ObservableInt(); 1088} 1089</pre> 1090<p> 1091 That's it! To access the value, use the set and get accessor methods: 1092</p> 1093 1094<pre> 1095user.firstName.set("Google"); 1096int age = user.age.get(); 1097</pre> 1098<h3 id="observable_collections"> 1099 Observable Collections 1100</h3> 1101 1102<p> 1103 Some applications use more dynamic structures to hold data. Observable 1104 collections allow keyed access to these data objects. 1105 {@link android.databinding.ObservableArrayMap} is 1106 useful when the key is a reference type, such as String. 1107</p> 1108 1109<pre> 1110ObservableArrayMap<String, Object> user = new ObservableArrayMap<>(); 1111user.put("firstName", "Google"); 1112user.put("lastName", "Inc."); 1113user.put("age", 17); 1114</pre> 1115<p> 1116 In the layout, the map may be accessed through the String keys: 1117</p> 1118 1119<pre> 1120<data> 1121 <import type="android.databinding.ObservableMap"/> 1122 <variable name="user" type="ObservableMap&lt;String, Object>"/> 1123</data> 1124… 1125<TextView 1126 android:text='@{user["lastName"]}' 1127 android:layout_width="wrap_content" 1128 android:layout_height="wrap_content"/> 1129<TextView 1130 android:text='@{String.valueOf(1 + (Integer)user["age"])}' 1131 android:layout_width="wrap_content" 1132 android:layout_height="wrap_content"/> 1133</pre> 1134<p> 1135 {@link android.databinding.ObservableArrayList} is useful when the key is an integer: 1136</p> 1137 1138<pre> 1139ObservableArrayList<Object> user = new ObservableArrayList<>(); 1140user.add("Google"); 1141user.add("Inc."); 1142user.add(17); 1143</pre> 1144<p> 1145 In the layout, the list may be accessed through the indices: 1146</p> 1147 1148<pre> 1149<data> 1150 <import type="android.databinding.ObservableList"/> 1151 <import type="com.example.my.app.Fields"/> 1152 <variable name="user" type="ObservableList&lt;Object>"/> 1153</data> 1154… 1155<TextView 1156 android:text='@{user[Fields.LAST_NAME]}' 1157 android:layout_width="wrap_content" 1158 android:layout_height="wrap_content"/> 1159<TextView 1160 android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}' 1161 android:layout_width="wrap_content" 1162 android:layout_height="wrap_content"/> 1163</pre> 1164<h2 id="generated_binding"> 1165 Generated Binding 1166</h2> 1167 1168<p> 1169 The generated binding class links the layout variables with the Views within 1170 the layout. As discussed earlier, the name and package of the Binding may be 1171 <a href="#custom_binding_class_names">customized</a>. The Generated binding 1172 classes all extend {@link android.databinding.ViewDataBinding}. 1173</p> 1174 1175<h3 id="creating"> 1176 Creating 1177</h3> 1178 1179<p> 1180 The binding should be created soon after inflation to ensure that the View 1181 hierarchy is not disturbed prior to binding to the Views with expressions 1182 within the layout. There are a few ways to bind to a layout. The most common 1183 is to use the static methods on the Binding class.The inflate method inflates 1184 the View hierarchy and binds to it all it one step. There is a simpler 1185 version that only takes a {@link android.view.LayoutInflater} and one that takes a 1186 {@link android.view.ViewGroup} as well: 1187</p> 1188 1189<pre> 1190MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater); 1191MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false); 1192</pre> 1193<p> 1194 If the layout was inflated using a different mechanism, it may be bound 1195 separately: 1196</p> 1197 1198<pre> 1199MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot); 1200</pre> 1201<p> 1202 Sometimes the binding cannot be known in advance. In such cases, the binding 1203 can be created using the {@link android.databinding.DataBindingUtil} class: 1204</p> 1205 1206<pre> 1207ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater, layoutId, 1208 parent, attachToParent); 1209ViewDataBinding binding = DataBindingUtil.bindTo(viewRoot, layoutId); 1210</pre> 1211<h3 id="views_with_ids"> 1212 Views With IDs 1213</h3> 1214 1215<p> 1216 A public final field will be generated for each View with an ID in the 1217 layout. The binding does a single pass on the View hierarchy, extracting the 1218 Views with IDs. This mechanism can be faster than calling findViewById for 1219 several Views. For example: 1220</p> 1221 1222<pre> 1223<layout xmlns:android="http://schemas.android.com/apk/res/android"> 1224 <data> 1225 <variable name="user" type="com.example.User"/> 1226 </data> 1227 <LinearLayout 1228 android:orientation="vertical" 1229 android:layout_width="match_parent" 1230 android:layout_height="match_parent"> 1231 <TextView android:layout_width="wrap_content" 1232 android:layout_height="wrap_content" 1233 android:text="@{user.firstName}" 1234 android:id="@+id/firstName"/> 1235 <TextView android:layout_width="wrap_content" 1236 android:layout_height="wrap_content" 1237 android:text="@{user.lastName}" 1238 android:id="@+id/lastName"/> 1239 </LinearLayout> 1240</layout> 1241</pre> 1242<p> 1243 Will generate a binding class with: 1244</p> 1245 1246<pre> 1247public final TextView firstName; 1248public final TextView lastName; 1249</pre> 1250<p> 1251 IDs are not nearly as necessary as without data binding, but there are still 1252 some instances where access to Views are still necessary from code. 1253</p> 1254 1255<h3 id="variables2"> 1256 Variables 1257</h3> 1258 1259<p> 1260 Each variable will be given accessor methods. 1261</p> 1262 1263<pre> 1264<data> 1265 <import type="android.graphics.drawable.Drawable"/> 1266 <variable name="user" type="com.example.User"/> 1267 <variable name="image" type="Drawable"/> 1268 <variable name="note" type="String"/> 1269</data> 1270</pre> 1271<p> 1272 will generate setters and getters in the binding: 1273</p> 1274 1275<pre> 1276public abstract com.example.User getUser(); 1277public abstract void setUser(com.example.User user); 1278public abstract Drawable getImage(); 1279public abstract void setImage(Drawable image); 1280public abstract String getNote(); 1281public abstract void setNote(String note); 1282</pre> 1283<h3 id="viewstubs"> 1284 ViewStubs 1285</h3> 1286 1287<p> 1288 {@link android.view.ViewStub}s are a little different from normal Views. They start off invisible 1289 and when they either are made visible or are explicitly told to inflate, they 1290 replace themselves in the layout by inflating another layout. 1291</p> 1292 1293<p> 1294 Because the <code>ViewStub</code> essentially disappears from the View hierarchy, the View 1295 in the binding object must also disappear to allow collection. Because the 1296 Views are final, a {@link android.databinding.ViewStubProxy} object takes the place of the 1297 <code>ViewStub</code>, giving the developer access to the ViewStub when it exists and also 1298 access to the inflated View hierarchy when the <code>ViewStub</code> has been inflated. 1299</p> 1300 1301<p> 1302 When inflating another layout, a binding must be established for the new 1303 layout. Therefore, the <code>ViewStubProxy</code> must listen to the <code>ViewStub</code>'s 1304 {@link android.view.ViewStub.OnInflateListener} and establish the binding at that time. Since 1305 only one can exist, the <code>ViewStubProxy</code> allows the developer to set an 1306 <code>OnInflateListener</code> on it that it will call after establishing the binding. 1307</p> 1308 1309<h3 id="advanced_binding"> 1310 Advanced Binding 1311</h3> 1312 1313<h4 id="dynamic_variables"> 1314 Dynamic Variables 1315</h4> 1316 1317<p> 1318 At times, the specific binding class won't be known. For example, a 1319 {@link android.support.v7.widget.RecyclerView.Adapter} operating against arbitrary layouts 1320 won't know the specific binding class. It still must assign the binding value during the 1321 {@link android.support.v7.widget.RecyclerView.Adapter#onBindViewHolder}. 1322</p> 1323 1324<p> 1325 In this example, all layouts that the RecyclerView binds to have an "item" 1326 variable. The <code>BindingHolder</code> has a <code>getBinding</code> method returning the 1327 {@link android.databinding.ViewDataBinding} base. 1328</p> 1329 1330<pre> 1331public void onBindViewHolder(BindingHolder holder, int position) { 1332 final T item = mItems.get(position); 1333 holder.getBinding().setVariable(BR.item, item); 1334 holder.getBinding().executePendingBindings(); 1335} 1336</pre> 1337<h4 id="immediate_binding"> 1338 Immediate Binding 1339</h4> 1340 1341<p> 1342 When a variable or observable changes, the binding will be scheduled to 1343 change before the next frame. There are times, however, when binding must be 1344 executed immediately. To force execution, use the 1345 {@link android.databinding.ViewDataBinding#executePendingBindings()} method. 1346</p> 1347 1348<h4> 1349 Background Thread 1350</h4> 1351 1352<p> 1353 You can change your data model in a background thread as long as it is not a 1354 collection. Data binding will localize each variable / field while evaluating 1355 to avoid any concurrency issues. 1356</p> 1357 1358<h2 id="attribute_setters"> 1359 Attribute Setters 1360</h2> 1361 1362<p> 1363 Whenever a bound value changes, the generated binding class must call a 1364 setter method on the View with the binding expression. The data binding 1365 framework has ways to customize which method to call to set the value. 1366</p> 1367 1368<h3 id="automatic_setters"> 1369 Automatic Setters 1370</h3> 1371For an attribute, data binding tries to find the method setAttribute. The 1372namespace for the attribute does not matter, only the attribute name itself. 1373<p> 1374 For example, an expression associated with TextView's attribute 1375 <strong><code>android:text</code></strong> will look for a setText(String). 1376 If the expression returns an int, data binding will search for a setText(int) 1377 method. Be careful to have the expression return the correct type, casting if 1378 necessary. Note that data binding will work even if no attribute exists with 1379 the given name. You can then easily "create" attributes for any setter by 1380 using data binding. For example, support DrawerLayout doesn't have any 1381 attributes, but plenty of setters. You can use the automatic setters to use 1382 one of these. 1383</p> 1384 1385<pre> 1386<android.support.v4.widget.<strong>DrawerLayout 1387 android:layout_width="wrap_content" 1388 android:layout_height="wrap_content" 1389 app:scrimColor="@{@color/scrim}" 1390 app:drawerListener="@{fragment.drawerListener}"/></strong> 1391</pre> 1392<h3 id="renamed_setters"> 1393 Renamed Setters 1394</h3> 1395 1396<p> 1397 Some attributes have setters that don't match by name. For these 1398 methods, an attribute may be associated with the setter through 1399 {@link android.databinding.BindingMethods} annotation. This must be associated with 1400 a class and contains {@link android.databinding.BindingMethod} annotations, one for 1401 each renamed method. For example, the <strong><code>android:tint</code></strong> attribute 1402 is really associated with {@link android.widget.ImageView#setImageTintList}, not 1403 <code>setTint</code>. 1404</p> 1405 1406<pre> 1407@BindingMethods({ 1408 @BindingMethod(type = "android.widget.ImageView", 1409 attribute = "android:tint", 1410 method = "setImageTintList"), 1411}) 1412</pre> 1413<p> 1414 It is unlikely that developers will need to rename setters; the android 1415 framework attributes have already been implemented. 1416</p> 1417 1418<h3 id="custom_setters"> 1419 Custom Setters 1420</h3> 1421 1422<p> 1423 Some attributes need custom binding logic. For example, there is no 1424 associated setter for the <strong><code>android:paddingLeft</code></strong> 1425 attribute. Instead, <code>setPadding(left, top, right, bottom)</code> exists. 1426 A static binding adapter method with the {@link android.databinding.BindingAdapter} 1427 annotation allows the developer to customize how a setter for an attribute is 1428 called. 1429</p> 1430 1431<p> 1432 The android attributes have already had <code>BindingAdapter</code>s created. 1433 For example, here is the one for <code>paddingLeft</code>: 1434</p> 1435 1436<pre> 1437@BindingAdapter("android:paddingLeft") 1438public static void setPaddingLeft(View view, int padding) { 1439 view.setPadding(padding, 1440 view.getPaddingTop(), 1441 view.getPaddingRight(), 1442 view.getPaddingBottom()); 1443} 1444</pre> 1445<p> 1446 Binding adapters are useful for other types of customization. For example, a 1447 custom loader can be called off-thread to load an image. 1448</p> 1449 1450<p> 1451 Developer-created binding adapters will override the data binding default 1452 adapters when there is a conflict. 1453</p> 1454 1455<p> 1456 You can also have adapters that receive multiple parameters. 1457</p> 1458 1459<pre> 1460@BindingAdapter({"bind:imageUrl", "bind:error"}) 1461public static void loadImage(ImageView view, String url, Drawable error) { 1462 Picasso.with(view.getContext()).load(url).error(error).into(view); 1463} 1464</pre> 1465<pre> 1466<ImageView app:imageUrl=“@{venue.imageUrl}” 1467app:error=“@{@drawable/venueError}”/> 1468</pre> 1469 1470<p> 1471 This adapter will be called if both <strong>imageUrl</strong> and 1472 <strong>error</strong> are used for an ImageView and <em>imageUrl</em> is a 1473 string and <em>error</em> is a drawable. 1474</p> 1475 1476<ul> 1477 <li>Custom namespaces are ignored during matching. 1478 </li> 1479 1480 <li>You can also write adapters for android namespace. 1481 </li> 1482</ul> 1483 1484<p> 1485 Binding adapter methods may optionally take the old values in their handlers. A method 1486 taking old and new values should have all old values for the attributes come first, followed 1487 by the new values: 1488</p> 1489<pre> 1490@BindingAdapter("android:paddingLeft") 1491public static void setPaddingLeft(View view, int oldPadding, int newPadding) { 1492 if (oldPadding != newPadding) { 1493 view.setPadding(newPadding, 1494 view.getPaddingTop(), 1495 view.getPaddingRight(), 1496 view.getPaddingBottom()); 1497 } 1498} 1499</pre> 1500<p> 1501 Event handlers may only be used with interfaces or abstract classes with one abstract method. 1502 For example: 1503</p> 1504<pre> 1505@BindingAdapter("android:onLayoutChange") 1506public static void setOnLayoutChangeListener(View view, View.OnLayoutChangeListener oldValue, 1507 View.OnLayoutChangeListener newValue) { 1508 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 1509 if (oldValue != null) { 1510 view.removeOnLayoutChangeListener(oldValue); 1511 } 1512 if (newValue != null) { 1513 view.addOnLayoutChangeListener(newValue); 1514 } 1515 } 1516} 1517</pre> 1518<p> 1519 When a listener has multiple methods, it must be split into multiple listeners. For example, 1520 {@link android.view.View.OnAttachStateChangeListener} has two methods: 1521 {@link android.view.View.OnAttachStateChangeListener#onViewAttachedToWindow onViewAttachedToWindow()} and 1522 {@link android.view.View.OnAttachStateChangeListener#onViewDetachedFromWindow onViewDetachedFromWindow()}. 1523 We must then create two interfaces to differentiate the attributes and handlers for them. 1524</p> 1525 1526<pre> 1527@TargetApi(VERSION_CODES.HONEYCOMB_MR1) 1528public interface OnViewDetachedFromWindow { 1529 void onViewDetachedFromWindow(View v); 1530} 1531 1532@TargetApi(VERSION_CODES.HONEYCOMB_MR1) 1533public interface OnViewAttachedToWindow { 1534 void onViewAttachedToWindow(View v); 1535} 1536</pre> 1537<p> 1538 Because changing one listener will also affect the other, we must have three different 1539 binding adapters, one for each attribute and one for both, should they both be set. 1540</p> 1541<pre> 1542@BindingAdapter("android:onViewAttachedToWindow") 1543public static void setListener(View view, OnViewAttachedToWindow attached) { 1544 setListener(view, null, attached); 1545} 1546 1547@BindingAdapter("android:onViewDetachedFromWindow") 1548public static void setListener(View view, OnViewDetachedFromWindow detached) { 1549 setListener(view, detached, null); 1550} 1551 1552@BindingAdapter({"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"}) 1553public static void setListener(View view, final OnViewDetachedFromWindow detach, 1554 final OnViewAttachedToWindow attach) { 1555 if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) { 1556 final OnAttachStateChangeListener newListener; 1557 if (detach == null && attach == null) { 1558 newListener = null; 1559 } else { 1560 newListener = new OnAttachStateChangeListener() { 1561 @Override 1562 public void onViewAttachedToWindow(View v) { 1563 if (attach != null) { 1564 attach.onViewAttachedToWindow(v); 1565 } 1566 } 1567 1568 @Override 1569 public void onViewDetachedFromWindow(View v) { 1570 if (detach != null) { 1571 detach.onViewDetachedFromWindow(v); 1572 } 1573 } 1574 }; 1575 } 1576 final OnAttachStateChangeListener oldListener = ListenerUtil.trackListener(view, 1577 newListener, R.id.onAttachStateChangeListener); 1578 if (oldListener != null) { 1579 view.removeOnAttachStateChangeListener(oldListener); 1580 } 1581 if (newListener != null) { 1582 view.addOnAttachStateChangeListener(newListener); 1583 } 1584 } 1585} 1586</pre> 1587<p> 1588 The above example is slightly more complicated than normal because View uses add and remove 1589 for the listener instead of a set method for {@link android.view.View.OnAttachStateChangeListener}. 1590 The <code>android.databinding.adapters.ListenerUtil</code> class helps keep track of the previous 1591 listeners so that they may be removed in the Binding Adaper. 1592</p> 1593<p> 1594 By annotating the interfaces <code>OnViewDetachedFromWindow</code> and 1595 <code>OnViewAttachedToWindow</code> with 1596 <code>@TargetApi(VERSION_CODES.HONEYCOMB_MR1)</code>, the data binding code 1597 generator knows that the listener should only be generated when running on Honeycomb MR1 1598 and new devices, the same version supported by 1599 {@link android.view.View#addOnAttachStateChangeListener}. 1600</p> 1601<h2 id="converters"> 1602 Converters 1603</h2> 1604 1605<h3 id="object_conversions"> 1606 Object Conversions 1607</h3> 1608 1609<p> 1610 When an Object is returned from a binding expression, a setter will be chosen 1611 from the automatic, renamed, and custom setters. The Object will be cast to a 1612 parameter type of the chosen setter. 1613</p> 1614 1615<p> 1616 This is a convenience for those using ObservableMaps to hold data. for 1617 example: 1618</p> 1619 1620<pre> 1621<TextView 1622 android:text='@{userMap["lastName"]}' 1623 android:layout_width="wrap_content" 1624 android:layout_height="wrap_content"/> 1625</pre> 1626 1627<p> 1628The <code>userMap</code> returns an Object and that Object will be automatically cast to 1629 parameter type found in the setter <code>setText(CharSequence)</code>. When there 1630 may be confusion about the parameter type, the developer will need 1631 to cast in the expression. 1632</p> 1633 1634<h3 id="custom_conversions">Custom Conversions</h3> 1635 1636<p> 1637 Sometimes conversions should be automatic between specific types. For 1638 example, when setting the background: 1639</p> 1640 1641<pre> 1642<View 1643 android:background="@{isError ? @color/red : @color/white}" 1644 android:layout_width="wrap_content" 1645 android:layout_height="wrap_content"/> 1646</pre> 1647<p> 1648 Here, the background takes a <code>Drawable</code>, but the color is an 1649 integer. Whenever a <code>Drawable</code> is expected and an integer is 1650 returned, the <code>int</code> should be converted to a 1651 <code>ColorDrawable</code>. This conversion is done using a static method 1652 with a BindingConversion annotation: 1653</p> 1654 1655<pre> 1656@BindingConversion 1657public static ColorDrawable convertColorToDrawable(int color) { 1658 return new ColorDrawable(color); 1659} 1660</pre> 1661<p> 1662 Note that conversions only happen at the setter level, so it is <strong>not 1663 allowed</strong> to mix types like this: 1664</p> 1665 1666<pre> 1667<View 1668 android:background="@{isError ? @drawable/error : @color/white}" 1669 android:layout_width="wrap_content" 1670 android:layout_height="wrap_content"/> 1671</pre> 1672