DataBinding 官方文檔翻譯學習筆記

Data Binding Library 數據綁定庫

  • This document explains how to use the Data Binding Library to write declarative layouts and minimize the glue code necessary to bind your application logic and layoutshtml

  • 本文介紹瞭如何使用數據綁定庫去寫聲明佈局文件和減小綁定你的應用程序的邏輯和佈局所必需的粘合代碼。java

  • The Data Binding Library offers both flexibility and broad compatibility — it's a support library, so you can use it with all Android platform versions back to Android 2.1 (API level 7+).android

  • 數據綁定庫是一個支持庫,它提供了靈活性和廣闊的兼容性,因此你能夠在版本Android2.1以後的全部android平臺中使用它。express

  • To use data binding, Android Plugin for Gradle 1.5.0-alpha1 or higher is required. See how to update the Android Plugin for Gradle.api

  • 使用數據綁定要求Android中的Gradle插件在1.5.0-alpha1 或者更高的版本。併發

Build Environment 構建環境

  • To get started with Data Binding, download the library from the Support repository in the Android SDK manager.app

  • 開始使用數據綁定庫前先要在Android SDK 管理者中從支持庫中下載該庫。框架

  • To configure your app to use data binding, add the dataBinding element to your build.gradle file in the app module.less

  • 在你的應用程序的模塊中的build.gradle文件中添加dataBinding元素去配置你的應用程序去使用數據綁定庫的功能。ide

  • Use the following code snippet to configure data binding:

  • 使用下面的代碼片斷去配置使用數據綁定

android {
    ....
    dataBinding {
        enabled = true
    }
}
  • If you have an app module that depends on a library which uses data binding, your app module must configure data binding in its build.gradle file as well.

  • 若是你有一個應用程序模塊依賴了一個使用數據綁定的庫,你的應用程序模塊一樣須要在build.gradle文件中配置數據綁定。

  • Also, make sure you are using a compatible version of Android Studio. Android Studio 1.3 and later provides support for data binding as described in Android Studio Support for Data Binding.

  • 此外,請確保你使用了一個兼容版本的Android Studio。Android Studio 1.3 以後的都爲數據綁定提供了支持。

Data Binding Layout Files 數據綁定佈局文件

Writing your first set of data binding expressions

寫你的第一組數據綁定表達式

  • Data-binding layout files are slightly different and start with a root tag of layout followed by a data element and a view root element. This view element is what your root would be in a non-binding layout file. A sample file looks like this:
  • 數據綁定佈局文件略有不一樣,在佈局開始的根標籤後要跟着一個數據元素和一個根視圖元素。你的根視圖元素jiang將在一個不具約束力的不懼文件中。看起來就想下面的示例文件:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>
  • The user variable within data describes a property that may be used within this layout.
  • 使用數據變量描述一個能夠在這個佈局文件內使用的屬性。
<variable name="user" type="com.example.User"/>
  • Expressions within the layout are written in the attribute properties using the "@{}" syntax. Here, the TextView's text is set to the firstName property of user:
  • 在佈局文件內使用"@{}"語法寫屬性,在這裏,TextView的text設置爲user的firstName屬性。
<TextView android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{user.firstName}"/>

Data Object 數據對象

  • Let's assume for now that you have a plain-old Java object (POJO) for User:
  • 讓咱們假設如今你有一個簡單的User Java對象(POJO)
public class User {
   public final String firstName;
   public final String lastName;
   public User(String firstName, String lastName) {
       this.firstName = firstName;
       this.lastName = lastName;
   }
}
  • This type of object has data that never changes. It is common in applications to have data that is read once and never changes thereafter. It is also possible to use a JavaBeans objects:
  • 這種類型的對象有一個永遠不會改變的數據。這種數據在應用程序中是常見的,這種數據一旦唄讀取一次就永遠不會被改變。此外也可使用JavaBeans對象。
public class User {
   private final String firstName;
   private final String lastName;
   public User(String firstName, String lastName) {
       this.firstName = firstName;
       this.lastName = lastName;
   }
   public String getFirstName() {
       return this.firstName;
   }
   public String getLastName() {
       return this.lastName;
   }
}
  • From the perspective of data binding, these two classes are equivalent. The expression @{user.firstName} used for the TextView's android:text attribute will access the firstName field in the former class and the getFirstName() method in the latter class. Alternatively, it will also be resolved to firstName() if that method exists.
  • 從數據綁定的觀點來看,這兩個類是等價的。TextView的android:text屬性經過使用表達式@{user.firsName}將得到模版類中的firsName字段和後面的類中的getFirsName()方法。或者,它也能夠被解析爲firstName(),若是該方法存在。

Binding Data 綁定數據

  • By default, a Binding class will be generated based on the name of the layout file, converting it to Pascal case and suffixing "Binding" to it. The above layout file was main_activity.xml so the generate class was MainActivityBinding. This class holds all the bindings from the layout properties (e.g. the user variable) to the layout's Views and knows how to assign values for the binding expressions.The easiest means for creating the bindings is to do it while inflating:

  • 默認的,將會根據佈局文件的名字生成一個綁定類,將其轉換爲Pascal的實例並在名字後面添加Binding做爲後綴.上述的佈局文件是main_activity.xml,因此生成類叫作MainActivityBinding.該類控制來自佈局的視圖中的佈局屬性中的全部綁定而且知道如何去爲綁定表達式分配值。在渲染布局時建立綁定是最簡單的方式。

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
   User user = new User("Test", "User");
   binding.setUser(user);
}
  • You're done! Run the application and you'll see Test User in the UI. Alternatively, you can get the view via:
  • 你已經完成!運行應用程序你將在UI中看到測試的用戶信息。或者,你能夠經過視圖其得到。
MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());
  • If you are using data binding items inside a ListView or RecyclerView adapter, you may prefer to use:

  • 若是你正在使用數據綁定一個ListView或者RecyclerView適配器中的項目,你可能更喜歡使用:

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
//or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

Event Handling 事件處理

  • Data Binding allows you to write expressions handling events that are dispatched from the views (e.g. onClick). Event attribute names are governed by the name of the listener method with a few exceptions. For example, View.OnLongClickListener has a method onLongClick(), so the attribute for this event is android:onLongClick. There are two ways to handle an event.

  • 數據綁定容許你寫表達式去處理來自視圖(點擊)的轉發的事件。經過監聽方法寧子管理事件屬性名單,有些例外。例如,View.onLongClickListener有一個onLongCkick()方法,因此對於該事件的屬性是android:onLongClick.如下是兩個方式去處理事件。

  1. Method References: In your expressions, you can reference methods that conform to the signature of the listener method. When an expression evaluates to a method reference, Data Binding wraps the method reference and owner object in a listener, and sets that listener on the target view. If the expression evaluates to null, Data Binding does not create a listener and sets a null listener instead.
  • 方法引用:在你的表達式中,你能夠引用符合監聽方法簽名的方法。當一個表達式評估一個方法引用時,數據綁定將方法的引用和監聽器中擁有的對象包裹起來而且將監聽器設置給目標對象。若是表達式評估是Null,數據綁定不會建立一個監聽器而是設置一個值爲null的監聽器合取代
  1. Listener Bindings: These are lambda expressions that are evaluated when the event happens. Data Binding always creates a listener, which it sets on the view. When the event is dispatched, the listener evaluates the lambda expression.
  • 監聽器綁定:當事件發生時,lambda表達式將被評估。數據綁定老是會建立一個監聽者,該監聽者會被設置到view上。當事件轉發的時候,監聽者評估該kambda表達式。

Method References 方法引用

  • Events can be bound to handler methods directly, similar to the way android: onClick can be assigned to a method in an Activity. One major advantage compared to the View#onClick attribute is that the expression is processed at compile time, so if the method does not exist or its signature is not correct, you receive a compile time error.

  • 事件能夠被直接綁定處處理方法上,與在一個Actuvity中使用android:onClick能夠被分配到一個方法上的方式相似。與設置View#onClick屬性相比一個主要的優點是該表達式在編譯時被處理,若是該方法不存在或者它的簽名不正確,你將收到一個編譯時錯誤。

  • The major difference between Method References and Listener Bindings is that the actual listener implementation is created when the data is bound, not when the event is triggered. If you prefer to evaluate the expression when the event happens, you should use listener binding.

  • 方法的引用和監聽者的綁定這兩種方式主要的不一樣是當數據綁定時被監聽者的是被真實的建立,而不是在事件觸發時。若是你更傾向與在事件發生時去評估該表達式,你應該使用監聽者綁定。

  • To assign an event to its handler, use a normal binding expression, with the value being the method name to call. For example, if your data object has two methods:

  • 使用值是做爲方法名的正常的綁定表達式去分配一個事件給處理程序。例如,若是你的數據對象有兩個方法。

public class MyHandlers {
    public void onClickFriend(View view) { ... }
}
  • The binding expression can assign the click listener for a View:

  • 綁定表達式能夠分配給視圖的點擊監聽者:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="handlers" type="com.example.Handlers"/>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"
           android:onClick="@{handlers::onClickFriend}"/>
   </LinearLayout>
</layout>
  • Note that the signature of the method in the expression must exactly match the signature of the method in the Listener object.
  • 注意在表達式中方法的簽名必須準確匹配監聽者對象中方法的簽名

Listener Bindings 監聽者綁定

  • Listener Bindings are binding expressions that run when an event happens. They are similar to method references, but they let you run arbitrary data binding expressions. This feature is available with Android Gradle Plugin for Gradle version 2.0 and later.

  • 監聽者的綁定是在一個事件發生時運行綁定的綁定表達式。他們相似方法的引用,但它們容許你運行任意的數據綁定表達式,該特性在使用Android Gradle插件且Gradle版本爲2.0以後是可用的。

  • In method references, the parameters of the method must match the parameters of the event listener. In Listener Bindings, only your return value must match the expected return value of the listener (unless it is expecting void). For example, you can have a presenter class that has the following method:

  • 在方法的綁定中,方法的參數必須匹配事件監聽者的參數。在監聽者綁定中,只有你的返回值必須匹配監聽者預期返回的值(除非它的愈切返回值是空)。例如,你能夠有一個持久化的類,該類有如下方法:

public class Presenter {
    public void onSaveClick(Task task){}
}
  • Then you can bind the click event to your class as follows:
  • 而後你可使用以下代碼綁定點時間到你的類。
<?xml version="1.0" encoding="utf-8"?>
  <layout xmlns:android="http://schemas.android.com/apk/res/android">
      <data>
          <variable name="task" type="com.android.example.Task" />
          <variable name="presenter" type="com.android.example.Presenter" />
      </data>
      <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
          <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
          android:onClick="@{() -> presenter.onSaveClick(task)}" />
      </LinearLayout>
  </layout>
  • Listeners are represented by lambda expressions that are allowed only as root elements of your expressions. When a callback is used in an expression, Data Binding automatically creates the necessary listener and registers for the event. When the view fires the event, Data Binding evaluates the given expression. As in regular binding expressions, you still get the null and thread safety of Data Binding while these listener expressions are being evaluated.

  • 對於你的表達式,只有做爲一個根元素,監聽者才容許用lambda表達式表示。

  • Note that in the example above, we haven't defined the view parameter that is passed into onClick(android.view.View). Listener bindings provide two choices for listener parameters: you can either ignore all parameters to the method or name all of them. If you prefer to name the parameters, you can use them in your expression. For example, the expression above could be written as:

  • 注意在上面的例子中,咱們尚未定義傳遞到onClick(View view)中的視圖參數。監聽者綁定隊友監聽參入提供兩種選擇:你能夠忽略全部方法的參數或者他們的名字。若是你更傾向於命名參數,你能夠在你的表達式中使用他們。例如,以上的表達式能夠被寫做:

android:onClick="@{(view) -> presenter.onSaveClick(task)}"
  • Or if you wanted to use the parameter in the expression, it could work as follows:
  • 或者若是你想在你表達式中去使用參數,它能夠做爲以下方式運行:
public class Presenter {
    public void onSaveClick(View view, Task task){}
}
android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"
  • You can use a lambda expression with more than one parameter:
  • 超過一個參數時你可使用一個lambad表達式
public class Presenter {
    public void onCompletedChanged(Task task, boolean completed){}
}
<CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
  • If the event you are listening to returns a value whose type is not void, your expressions must return the same type of value as well. For example, if you want to listen for the long click event, your expression should return boolean.
  • 若是你監聽的事件返回了一個類型不是void 的值,你的表達式必須返回同樣類型的值。例如,若是你想去監聽長點擊事件,你的表達式應該返回布爾類型。
public class Presenter {
    public boolean onLongClick(View view, Task task){}
}
android:onLongClick="@{(theView) -> presenter.onLongClick(theView, task)}"
  • If the expression cannot be evaluated due to null objects, Data Binding returns the default Java value for that type. For example, null for reference types, 0 for int, false for boolean, etc.

  • 若是表達式由於空對象不能被評估,數不綁定返回一個默認類型的Java值。例如,Null對應引用類型,0對應整型,false對應布爾類型。

  • If you need to use an expression with a predicate (e.g. ternary), you can use void as a symbol.

  • 若是你須要在表達式中使用斷言,你可使用void做爲一個標誌。

android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"

Avoid Complex Listeners 避開復合監聽

  • Listener expressions are very powerful and can make your code very easy to read. On the other hand, listeners containing complex expressions make your layouts hard to read and unmaintainable. These expressions should be as simple as passing available data from your UI to your callback method. You should implement any business logic inside the callback method that you invoked from the listener expression.

  • 監聽表達式是很是強大的,它能夠提升你的代碼的可讀性。另外一方面,監聽者包含的複合表達式增長你的佈局的閱讀難度和不可維護。對於你的回調方法的表達式應該儘量簡單就像經過你的UI的傳遞可用的數據給你的回調方法同樣。你應該在從監聽表達式調用的回調方法中事件全部的業務邏輯。

  • Some specialized click event handlers exist and they need an attribute other than android: onClick to avoid a conflict. The following attributes have been created to avoid such conflicts:

  • 存在一些專門的單擊事件處理程序須要比android: onClick多一個其餘的屬性以免衝突。如下的屬性被建立去避免衝突:

Class	         Listener Setter	                                 Attribute
SearchView	setOnSearchClickListener(View.OnClickListener)	android:onSearchClick
ZoomControls	setOnZoomInClickListener(View.OnClickListener)	android:onZoomIn
ZoomControls	setOnZoomOutClickListener(View.OnClickListener)	android:onZoomOut

Layout Details 佈局詳情

Imports

  • Zero or more import elements may be used inside the data element. These allow easy reference to classes inside your layout file, just like in Java.

  • 零個或者更多被導入的元素能夠在數據元素裏面使用。在你的佈局文件裏能夠就像在Java裏 面同樣很容易的引用類。

<data>
    <import type="android.view.View"/>
</data>
  • Now, View may be used within your binding expression:

  • 如今,能夠在你的綁定表達式裏面使用View

<TextView
   android:text="@{user.lastName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
  • When there are class name conflicts, one of the classes may be renamed to an "alias:"

  • 當類名衝突時,一個類可使用別名。

<import type="android.view.View"/>
<import type="com.example.real.estate.View"
        alias="Vista"/>
  • Now, Vista may be used to reference the com.example.real.estate.View and View may be used to reference android.view.View within the layout file. Imported types may be used as type references in variables and expressions:
  • 如今,在佈局文件理Vista能夠被使用去引用 com.example.real.estate.View而且View也能夠被使用去引用com.example.real.estate.View。在變涼和表達式中導入類型能夠被做爲類型引用去使用。
<data>
    <import type="com.example.User"/>
    <import type="java.util.List"/>
    <variable name="user" type="User"/>
    <variable name="userList" type="List&lt;User&gt;"/>
</data>
  • Note: Android Studio does not yet handle imports so the autocomplete for imported variables may not work in your IDE. Your application will still compile fine and you can work around the IDE issue by using fully qualified names in your variable definitions.
  • 注意:Android Studio至今不能處理導入,因此在你的IDE中自動導入變量不能工做。您的應用程序仍然能夠很好地編譯,你能夠經過在變量定義使用徹底合格的名稱解決此問題的IDE。
<TextView
   android:text="@{((User)(user.connection)).lastName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
  • Imported types may also be used when referencing static fields and methods in expressions:

  • 當用引用靜態字段和方法時,也能夠在表達式中使用導入的類型。

<data>
    <import type="com.example.MyStringUtils"/>
    <variable name="user" type="com.example.User"/>
</data>
…
<TextView
   android:text="@{MyStringUtils.capitalize(user.lastName)}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
  • Just as in Java, java.lang.* is imported automatically.

  • 就像在Java中同樣,java.lang.*是自動導入的

Variables

  • Any number of variable elements may be used inside the data element. Each variable element describes a property that may be set on the layout to be used in binding expressions within the layout file.
  • 任何變量元素的成員均可以在數據元素裏面使用。每個變量元素描述一個屬性,該屬性能夠在佈局文件的佈局裏經過使用綁定表達式設置。
<data>
    <import type="android.graphics.drawable.Drawable"/>
    <variable name="user"  type="com.example.User"/>
    <variable name="image" type="Drawable"/>
    <variable name="note"  type="String"/>
</data>
  • The variable types are inspected at compile time, so if a variable implements Observable or is an observable collection, that should be reflected in the type. If the variable is a base class or interface that does not implement the Observable* interface, the variables will not be observed!

  • 變量類型在編譯時檢查,因此若是一個變量實現了Observable或者是一個obsevable集合,在類型中該變量應該被反射。若是該變涼是一個基本類型或者沒有實現Observable及其子類接口的接口,該變量就不能被觀察!

  • When there are different layout files for various configurations (e.g. landscape or portrait), the variables will be combined. There must not be conflicting variable definitions between these layout files.

  • 當在不一樣的佈局文件中且各個佈局文件的配置也不一樣時,該變涼將被整合。在那些佈局文件之間變量的定義絕對不能有衝突。

  • The generated binding class will have a setter and getter for each of the described variables. The variables will take the default Java values until the setter is called — null for reference types, 0 for int, false for boolean, etc.

  • 生成的綁定類對於每個描述的變量將會生成一個setter和getter構造器。在setter方法被調用以前該變量將得到一個默認的Java值-引用是null,整型是0,布爾類型是false

  • A special variable named context is generated for use in binding expressions as needed. The value for context is the Context from the root View's getContext(). The context variable will be overridden by an explicit variable declaration with that name.

  • 爲了使用綁定表達式中,生成一個特殊的被成爲上下文的變量是必須的。該上下文的值就是來自於根視圖中經過getContext()方法得到的上下文。該上下文變量將被一個使用名字顯示聲明的變量覆蓋。

Custom Binding Class Names 自定義綁定類名字

  • By default, a Binding class is generated based on the name of the layout file, starting it with upper-case, removing underscores ( _ ) and capitalizing the following letter and then suffixing "Binding". This class will be placed in a databinding package under the module package. For example, the layout file contact_item.xml will generate ContactItemBinding. If the module package is com.example.my.app, then it will be placed in com.example.my.app.databinding.

  • 默認的,一個綁定類是基於佈局文件的名字進行生成,使用大寫開始,移除下劃線(_)而且後面跟着的字大寫而後添加Binding後綴。該類獎盃放置在模塊包下的databinding包中。例如,佈局文件contact_item.xml將生成ContactItemBinding.若是模塊包是com.example.myapp,那麼該類將被放置在com.example.myapp.databinding包中。

  • Binding classes may be renamed or placed in different packages by adjusting the class attribute of the data element. For example:

  • 綁定類的名字能夠經過調整數據元素中類的屬性能夠重命名。例如:

<data class="ContactItem">
    ...
</data>
  • This generates the binding class as ContactItem in the databinding package in the module package. If the class should be generated in a different package within the module package, it may be prefixed with ".":
  • 生成的ContactItem綁定類再模塊包下的databinding包中,若是但願該類在模塊包下不一樣的包中,可使用.前綴。
<data class=".ContactItem">
    ...
</data>
  • In this case, ContactItem is generated in the module package directly. Any package may be used if the full package is provided:
  • 在這種狀況下,ContactItem直接生成在模塊包下,若是提供完整的包,任何包均可以使用它。
<data class="com.example.ContactItem">
    ...
</data>

Includes

  • Variables may be passed into an included layout's binding from the containing layout by using the application namespace and the variable name in an attribute:
  • 來自於包含佈局的變量能夠在一個屬性中經過使用應用程序命名空間和和變量名傳入一個被included進來的綁定佈局中
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:bind="http://schemas.android.com/apk/res-auto">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <include layout="@layout/name"
           bind:user="@{user}"/>
       <include layout="@layout/contact"
           bind:user="@{user}"/>
   </LinearLayout>
</layout>
  • Here, there must be a user variable in both the name.xml and contact.xml layout files.

  • 這裏的name.xml和contact.xml佈局文件中都必須有一個user變量

  • Data binding does not support include as a direct child of a merge element. For example, the following layout is not supported:

  • 數據綁定不支持在做爲一個merge元素的直接子元素進行include操做。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:bind="http://schemas.android.com/apk/res-auto">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <merge>
       <include layout="@layout/name"
           bind:user="@{user}"/>
       <include layout="@layout/contact"
           bind:user="@{user}"/>
   </merge>
</layout>

Expression Language 表達式語言

Common Features 經常使用特性

  • The expression language looks a lot like a Java expression. These are the same:

  • 表達式語言看上去很像java表達式。下面是一些相同的部分

  • Mathematical + - / * % 數學運算

  • String concatenation + 字符串鏈接

  • Logical && || 邏輯運算符

  • Binary & | ^ 位運算符

  • Unary + - ! ~ 一元運算符

  • Shift >> >>> << 位移運算

  • Comparison == > < >= <= 比較運算

  • instanceof 判斷實例類型

  • Grouping () 分組

  • Literals - character, String, numeric, null

  • Cast

  • Method calls

  • Field access

  • Array access []

  • Ternary operator ?:

Examples: 例子

android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'

Missing Operations 沒有的操做

  • A few operations are missing from the expression syntax that you can use in Java.

  • 一些能夠在Java中使用的操做在表達式語法中是沒有的

  • this

  • super

  • new

  • Explicit generic invocation

Null Coalescing Operator Null 的聚合操做

The null coalescing operator (??) chooses the left operand if it is not null or the right if it is null. null聚合操做(??)若是不爲null選擇左邊的操做數,若是爲null,選擇右邊的操做數

android:text="@{user.displayName ?? user.lastName}"
  • This is functionally equivalent to:
  • 如下的功能是等價的
android:text="@{user.displayName != null ? user.displayName : user.lastName}"

#Property Reference 屬性引用

  • The first was already discussed in the Writing your first data binding expressions above: short form JavaBean references. When an expression references a property on a class, it uses the same format for fields, getters, and ObservableFields.
  • 在上面有關JavaBean的使用部分中已經討論瞭如何寫你的第一個數據綁定表達式。當表達式引用了一個類的屬性時,他要使用同樣的fields,getters,ObservableFields
android:text="@{user.lastName}"

#Avoiding NullPointerException 避免空指針異常

  • Generated data binding code automatically checks for nulls and avoid null pointer exceptions. For example, in the expression @{user.name}, if user is null, user.name will be assigned its default value (null). If you were referencing user.age, where age is an int, then it would default to 0.

  • 生成的數據綁定代碼會自動檢查空引用和空指針異常。例如,在表達式@{user.name},若是user是null,user.name將被配置一個默認的null值。若是你引用user.age,age是一個int類型字段,那麼他將默認是0.

#Collections 集合

  • Common collections: arrays, lists, sparse lists, and maps, may be accessed using the [] operator for convenience.
<data>
    <import type="android.util.SparseArray"/>
    <import type="java.util.Map"/>
    <import type="java.util.List"/>
    <variable name="list" type="List&lt;String&gt;"/>
    <variable name="sparse" type="SparseArray&lt;String&gt;"/>
    <variable name="map" type="Map&lt;String, String&gt;"/>
    <variable name="index" type="int"/>
    <variable name="key" type="String"/>
</data>
…
android:text="@{list[index]}"
…
android:text="@{sparse[index]}"
…
android:text="@{map[key]}"

#String Literals

  • When using single quotes around the attribute value, it is easy to use double quotes in the expression:
android:text='@{map["firstName"]}'
  • It is also possible to use double quotes to surround the attribute value. When doing so, String literals should either use the ' or back quote (`).
android:text="@{map[`firstName`}"
android:text="@{map['firstName']}"

#Resources

  • It is possible to access resources as part of expressions using the normal syntax:
  • 使用正常的表達式語法能夠得到資源
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
  • Format strings and plurals may be evaluated by providing parameters:
  • 格式化字符串和複數能夠經過提供的參數進行評估:
android:text="@{@string/nameFormat(firstName, lastName)}"
android:text="@{@plurals/banana(bananaCount)}"
  • When a plural takes multiple parameters, all parameters should be passed:
  • 當一個複數採用多個參數是,全部的參數都應該被傳入。
Have an orange
  Have %d oranges

android:text="@{@plurals/orange(orangeCount, 
orangeCount)}"
  • Some resources require explicit type evaluation.
  • 一些資源要求明確評估類型
Type	           Normal Reference	   Expression Reference
String[]	        @array     	         @stringArray
int[]	            @array	             @intArray
TypedArray          @array           	 @typedArray
Animator	        @animator	         @animator
StateListAnimator   @animator	         @stateListAnimator
color int	        @color	             @color
ColorStateList	    @color	             @colorStateList

Data Objects

  • Any plain old Java object (POJO) may be used for data binding, but modifying a POJO will not cause the UI to update. The real power of data binding can be used by giving your data objects the ability to notify when data changes. There are three different data change notification mechanisms, Observable objects, observable fields, and observable collections.

  • 數據綁定可使用全部的Java對象(POJO),可是修改一個POJO不會引發一個UI的更新。經過給予你的數據對象一個在數據發生變化時能夠通知的能力來使用數據綁定真正強大的能力。這是三個不一樣的數據改變通知機制,Observable對象,observable字段,observable集合

  • When one of these observable data object is bound to the UI and a property of the data object changes, the UI will be updated automatically.

  • 當被綁定到UI中的有一個是observable數據對象時,若是數據對象的屬性值改變了,UI也會自動更新。

Observable Objects

  • A class implementing the Observable interface will allow the binding to attach a single listener to a bound object to listen for changes of all properties on that object.
  • 一個實現了Observable接口的類將容許給綁定對象綁定關聯一個監聽器去監聽該對象中全部屬性的變化狀況。
  • The Observable interface has a mechanism to add and remove listeners, but notifying is up to the developer. To make development easier, a base class, BaseObservable, was created to implement the listener registration mechanism. The data class implementer is still responsible for notifying when the properties change. This is done by assigning a Bindable annotation to the getter and notifying in the setter.
  • Observable接口有一個添加和移除監聽器的機制,而已通知是在不斷的發展改進的。建立一個基本的BaseObservable類區實現監聽器註冊機制對於開發來講是很容易的。經過分配一個Bindable註解給數據類的getter和setter,當屬性改變時,數據類的視線仍然能響應通知。
private static class User extends BaseObservable {
   private String firstName;
   private String lastName;
   @Bindable
   public String getFirstName() {
       return this.firstName;
   }
   @Bindable
   public String getLastName() {
       return this.lastName;
   }
   public void setFirstName(String firstName) {
       this.firstName = firstName;
       notifyPropertyChanged(BR.firstName);
   }
   public void setLastName(String lastName) {
       this.lastName = lastName;
       notifyPropertyChanged(BR.lastName);
   }
}
  • The Bindable annotation generates an entry in the BR class file during compilation. The BR class file will be generated in the module package. If the base class for data classes cannot be changed, the Observable interface may be implemented using the convenient PropertyChangeRegistry to store and notify listeners efficiently.

  • 在編譯的時候,Bindable註解在BR類文件中生成一個條目。在模塊包下生成一個BR文件。若是數據類是一個不能改變的類,Observable接口會經過使用適當的PropertyChangeRegister去有效的存儲和通知監聽者來實現。

#ObservableFields

  • A little work is involved in creating Observable classes, so developers who want to save time or have few properties may use ObservableField and its siblings ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, and ObservableParcelable. ObservableFields are self-contained observable objects that have a single field. The primitive versions avoid boxing and unboxing during access operations. To use, create a public final field in the data class:
  • 在建立Observable類時仍是要作一些工做的,因此一些想去解約事件或者但願有一些可以使用的屬性的開發着可使用ObservableField和與之相似的ObservableBoolean,ObservableByte,ObservableChar,ObservableDouble,ObservableLong,ObservableFloat,ObservableDouble,ObservableParcelable。ObservableFields 是一個有單一字段的自包含的observable對象。最初的版本是避免在操做時作裝箱和拆箱操做。在數據類中以public final 字段形式建立並使用。
private static class User {
   public final ObservableField<String> firstName =
       new ObservableField<>();
   public final ObservableField<String> lastName =
       new ObservableField<>();
   public final ObservableInt age = new ObservableInt();
}
  • That's it! To access the value, use the set and get accessor methods:
  • 就是這樣,使用set和get方法去獲取值
user.firstName.set("Google");
int age = user.age.get();

Observable Collections

  • Some applications use more dynamic structures to hold data. Observable collections allow keyed access to these data objects. ObservableArrayMap is useful when the key is a reference type, such as String.

  • 一些應用更多地使用動態結構去控制數據。Observable collections 容許鍵值對的形勢去獲取數據對象。ObservableArrayMap是很經常使用的一個,它的key是一個引用類型,好比String。

ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);
  • In the layout, the map may be accessed through the String keys:

  • 在佈局中,能夠經過String類型的key訪問map。

<data>
    <import type="android.databinding.ObservableMap"/>
    <variable name="user" type="ObservableMap&lt;String, Object&gt;"/>
</data>
…
<TextView
   android:text='@{user["lastName"]}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
<TextView
   android:text='@{String.valueOf(1 + (Integer)user["age"])}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
  • ObservableArrayList is useful when the key is an integer:

  • ObservableArrayList 也是很經常使用的,它的key是一個integer:

ObservableArrayList<Object> user = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add(17);
  • In the layout, the list may be accessed through the indices:

  • 在佈局中能夠經過 下標訪問list

<data>
    <import type="android.databinding.ObservableList"/>
    <import type="com.example.my.app.Fields"/>
    <variable name="user" type="ObservableList&lt;Object&gt;"/>
</data>
…
<TextView
   android:text='@{user[Fields.LAST_NAME]}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
<TextView
   android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

Generated Binding

  • The generated binding class links the layout variables with the Views within the layout. As discussed earlier, the name and package of the Binding may be customized. The Generated binding classes all extend ViewDataBinding.

  • 使用Views內部的layout能夠將生成的綁定類於佈局變量連接起來。就像前面討論的同樣,綁定的包名可疑被自定義。全部生成的綁定類都繼承ViewDataBinding這個類

Creating

  • The binding should be created soon after inflation to ensure that the View hierarchy is not disturbed prior to binding to the Views with expressions within the layout. There are a few ways to bind to a layout. The most common is to use the static methods on the Binding class.The inflate method inflates the View hierarchy and binds to it all it one step. There is a simpler version that only takes a LayoutInflater and one that takes a ViewGroup as well:
  • 在View被inflation後應該儘快建立綁定,這樣能確保在layout裏用表達式綁定View以前View的層級不被幹擾。如下是幾種綁定layout的方式。最經常使用的是在綁定類上使用靜態方法inflate方法去Inflates View的層級和綁定它,全部操做只須要一步完成。這是i 個簡單版本的方法,裏面只使用一噶LayoutInflater和一個ViewGroup:
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater);
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false);
  • If the layout was inflated using a different mechanism, it may be bound separately:

  • 若是layout是經過不一樣的機制進行inflated,那麼它能夠被單獨地綁定。

MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);
  • Sometimes the binding cannot be known in advance. In such cases, the binding can be created using the DataBindingUtil class:

  • 有時,咱們並不能預先知道綁定的東西。在這種狀況下,可使用DataBindingUtils類去建立綁定。

ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater, layoutId,
    parent, attachToParent);
ViewDataBinding binding = DataBindingUtil.bindTo(viewRoot, layoutId);

Views With IDs

  • A public final field will be generated for each View with an ID in the layout. The binding does a single pass on the View hierarchy, extracting the Views with IDs. This mechanism can be faster than calling findViewById for several Views. For example:

  • 在layout中使用View的一個ID爲每一個View生成一個public final類型的字段。在View的層級中,綁定根據IDs提取View並簡單的傳入View的層級中。這個機制比經過調用各類Views的findViewById方法獲取View更加的快速。例如:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"
   android:id="@+id/firstName"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"
  android:id="@+id/lastName"/>
   </LinearLayout>
</layout>
  • Will generate a binding class with:

  • 將會使用以下代碼生成一個綁定類:

public final TextView firstName;
public final TextView lastName;
  • IDs are not nearly as necessary as without data binding, but there are still some instances where access to Views are still necessary from code.

  • 若是沒有數據綁定,IDs並非必須的,可是仍然有些狀況下須要從代碼裏面訪問Views時,IDs仍然是須要的。

Variables 變量

  • Each variable will be given accessor methods.
  • 每個變量都將被給予一個存儲器方法
<data>
    <import type="android.graphics.drawable.Drawable"/>
    <variable name="user"  type="com.example.User"/>
    <variable name="image" type="Drawable"/>
    <variable name="note"  type="String"/>
</data>
  • will generate setters and getters in the binding:
  • 在綁定時將會生成一個setters和一個getters存儲器
public abstract com.example.User getUser();
public abstract void setUser(com.example.User user);
public abstract Drawable getImage();
public abstract void setImage(Drawable image);
public abstract String getNote();
public abstract void setNote(String note);

ViewStubs

  • ViewStubs are a little different from normal Views. They start off invisible and when they either are made visible or are explicitly told to inflate, they replace themselves in the layout by inflating another layout.

  • ViewStubs 與通常的Views有些許不一樣。ViewStubs開始時通常時不可見的,當ViewStubs被置爲可見的活着明確調用inflate,ViewStubs將會使用其餘的layout替換自己。

  • Because the ViewStub essentially disappears from the View hierarchy, the View in the binding object must also disappear to allow collection. Because the Views are final, a ViewStubProxy object takes the place of the ViewStub, giving the developer access to the ViewStub when it exists and also access to the inflated View hierarchy when the ViewStub has been inflated.

  • 由於從View的層級中ViewStub自己並不會被渲染出來,綁定對象中的View對於collection也必須容許其消失。由於這個Views是final的,當ViewStub已經被inflated且在ViewStubProxy對象取代ViewStub的位置時,若是得到了View的層級的ViewStub是存的,開發者便能得到該ViewStub。

  • When inflating another layout, a binding must be established for the new layout. Therefore, the ViewStubProxy must listen to the ViewStub's ViewStub.OnInflateListener and establish the binding at that time. Since only one can exist, the ViewStubProxy allows the developer to set an OnInflateListener on it that it will call after establishing the binding.

  • 在inflating其餘的layout時,對於一個新的layout,一個綁定必須是明確的。所以,ViewStubProxy必須監聽ViewStubs的ViewStub.OnInflateListener 而且明確這綁定的時間。ViewStubProxy只容許開發者去設置一個OnInflateListener,在明確地綁定時,該監聽者將被調用。

Advanced Binding 高級綁定

Dynamic Variables 動態變量

  • At times, the specific binding class won't be known. For example, a RecyclerView.Adapter operating against arbitrary layouts won't know the specific binding class. It still must assign the binding value during the onBindViewHolder(VH, int).

  • 有時,特殊的綁定類不能被瞭解。例如,一個RecyclerView.Adapter 的操做違反了任意佈局不能知道指定的綁定類。當onBindViewHolder(VH,int)回調時它仍然可以被分配到綁定的值。

  • In this example, all layouts that the RecyclerView binds to have an "item" variable. The BindingHolder has a getBinding method returning the ViewDataBinding base.

  • 好比如下例子,RecyclerView的全部佈局綁定一個item變量。BindinngHolder又一個getBinding方法,該方法返回基本的ViewDataBinding。

public void onBindViewHolder(BindingHolder holder, int position) {
   final T item = mItems.get(position);
   holder.getBinding().setVariable(BR.item, item);
   holder.getBinding().executePendingBindings();
}

###Immediate Binding 當即綁定

  • When a variable or observable changes, the binding will be scheduled to change before the next frame. There are times, however, when binding must be executed immediately. To force execution, use the executePendingBindings() method.
  • 當一個變量活着observable變化時,在下一幀前綁定操做將被調度去改變。然而,有時綁定必須被當即調用,可使用executePendingBindings()方法。

Background Thread 後臺線程

  • You can change your data model in a background thread as long as it is not a collection. Data binding will localize each variable / field while evaluating to avoid any concurrency issues.
  • 你也能夠在儘量長耗時的後臺線程去改變你的數據模型,該模型不是一個collection.當產生避免任何併發行問題的評估操做時,數據綁定將使每個變量/字段局域化。

Attribute Setters 屬性設置

  • Whenever a bound value changes, the generated binding class must call a setter method on the View with the binding expression. The data binding framework has ways to customize which method to call to set the value.
  • 每當一個綁定值發生改變時,使用綁定表達式的View對應生成的綁定類都必須調用setter方法。數據綁定框架有多種方式去自定義被調用去設置改變的值的方法。

Automatic Setters 自動設置

  • For an attribute, data binding tries to find the method setAttribute. The namespace for the attribute does not matter, only the attribute name itself.

  • 對於一個屬性,數據綁定嘗試着去查找setAttribute的方法。於屬性的命名空間沒有關係,只與屬性自己的名字有關。

  • For example, an expression associated with TextView's attribute android:text will look for a setText(String). If the expression returns an int, data binding will search for a setText(int) method. Be careful to have the expression return the correct type, casting if necessary. Note that data binding will work even if no attribute exists with the given name. You can then easily "create" attributes for any setter by using data binding. For example, support DrawerLayout doesn't have any attributes, but plenty of setters. You can use the automatic setters to use one of these.

  • 例如,一個與TextView的android : text關聯的表達式就會查找一個setText(String) 的方法。若是該表達式返回一個int值,數據綁定會繼續搜索一個setText(int)的方法。若是有須要,要特別注意表達式返回正確類型。

<android.support.v4.widget.DrawerLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:scrimColor="@{@color/scrim}"
    app:drawerListener="@{fragment.drawerListener}"/>

###Renamed Setters 重命名Setters

  • Some attributes have setters that don't match by name. For these methods, an attribute may be associated with the setter through BindingMethods annotation. This must be associated with a class and contains BindingMethod annotations, one for each renamed method. For example, the android:tint attribute is really associated with setImageTintList(ColorStateList), not setTint.
  • 一些屬性的setters不能經過名字進行匹配。對於此種狀況,咱們可使用BindingMethods註解將一個屬性和setter進行關聯。對於每一個重命名的方法,該方法必須屬於一個類而且包含BindingMethod註解。例如,android:tint 屬性其實是魚setImageTintList(ColorStateList)方法相關聯,而不是setTint方法。
@BindingMethods({
       @BindingMethod(type = "android.widget.ImageView",
                      attribute = "android:tint",
                      method = "setImageTintList"),
})
  • It is unlikely that developers will need to rename setters; the android framework attributes have already been implemented.
  • Android框架的屬性早已經被實現,開發者去重命名框架的方法是不可能的。

Custom Setters 自定義setters

  • Some attributes need custom binding logic. For example, there is no associated setter for the android:paddingLeft attribute. Instead, setPadding(left, top, right, bottom) exists. A static binding adapter method with the BindingAdapter annotation allows the developer to customize how a setter for an attribute is called.

  • 一些屬性須要自定義綁定邏輯。例如,對於android:paddingLeft屬性是與setter沒有聯繫的。而是與setPadding(left,top,right,bottom)方法相關聯。使用BindingAdapter註解的一個靜態綁定適配器的方法容許開發者去定義該屬性的setter方法被調用時作些什麼。

  • The android attributes have already had BindingAdapters created. For example, here is the one for paddingLeft:

  • android的屬性早已被BindingAdaoters建立。例如,這是一個paddingLeft的例子:

@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int padding) {
   view.setPadding(padding,
                   view.getPaddingTop(),
                   view.getPaddingRight(),
                   view.getPaddingBottom());
}
  • Binding adapters are useful for other types of customization. For example, a custom loader can be called off-thread to load an image.

  • 綁定適配器對於自定義的類型是頗有用的。例如,一個自定的一加載器能夠調用離線的線程去加載一個圖像。

  • Developer-created binding adapters will override the data binding default adapters when there is a conflict.

  • 當有衝突的時候,被開發者建立的綁定適配器將被默認的綁數據綁定適配器覆蓋。

  • You can also have adapters that receive multiple parameters.

  • 你也能夠有一個接收多個參數的適配器

@BindingAdapter({"bind:imageUrl", "bind:error"})
public static void loadImage(ImageView view, String url, Drawable error) {
   Picasso.with(view.getContext()).load(url).error(error).into(view);
}
<ImageView app:imageUrl="@{venue.imageUrl}"
app:error="@{@drawable/venueError}"/>

This adapter will be called if both imageUrl and error are used for an ImageView and imageUrl is a string and error is a drawable.

若是被一個ImageView使用的imageUrl錯誤或者imageUrl是一個錯誤的drawable字符串,該適配器都會被調用

  • Custom namespaces are ignored during matching.

  • 自定義命名空間在匹配的過程當中被忽略

  • You can also write adapters for android namespace.

  • 你也能夠對android命名空間寫一個適配器

Binding adapter methods may optionally take the old values in their handlers. A method taking old and new values should have all old values for the attributes come first, followed by the new values:

在他們的處理程序中,綁定適配器的方法能夠隨意的得到舊的值。一個方法得到舊的值和新的值的時候,首先得到的是該屬性的全部舊的值,而後纔是新的值。

@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int oldPadding, int newPadding) {
   if (oldPadding != newPadding) {
       view.setPadding(newPadding,
                       view.getPaddingTop(),
                       view.getPaddingRight(),
                       view.getPaddingBottom());
   }
}
  • Event handlers may only be used with interfaces or abstract classes with one abstract method. For example:
  • 事件處理程序僅能夠和接口或者抽象類的一個抽象方法一塊兒使用。例如:
@BindingAdapter("android:onLayoutChange")
public static void setOnLayoutChangeListener(View view, View.OnLayoutChangeListener oldValue,
       View.OnLayoutChangeListener newValue) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        if (oldValue != null) {
            view.removeOnLayoutChangeListener(oldValue);
        }
        if (newValue != null) {
            view.addOnLayoutChangeListener(newValue);
        }
    }
}
  • When a listener has multiple methods, it must be split into multiple listeners. For example, View.OnAttachStateChangeListener has two methods: onViewAttachedToWindow() and onViewDetachedFromWindow(). We must then create two interfaces to differentiate the attributes and handlers for them.
  • 當一個監聽者有多個方法時,它必須被分割成多個簡體器。例如,View.OnAttachStateChangeListener 有兩個方法:onViewAttachedToWindow()和onViewDetachdFromWindow().咱們必須爲該屬性建立兩個不一樣的接口並處理它們。
@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewDetachedFromWindow {
    void onViewDetachedFromWindow(View v);
}

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewAttachedToWindow {
    void onViewAttachedToWindow(View v);
}
  • Because changing one listener will also affect the other, we must have three different binding adapters, one for each attribute and one for both, should they both be set.
  • 對於每個應該被設置的屬性,咱們必須有多個不一樣的綁定適配器,由於改變一個監聽器也會影響另一個,
@BindingAdapter("android:onViewAttachedToWindow")
public static void setListener(View view, OnViewAttachedToWindow attached) {
    setListener(view, null, attached);
}

@BindingAdapter("android:onViewDetachedFromWindow")
public static void setListener(View view, OnViewDetachedFromWindow detached) {
    setListener(view, detached, null);
}

@BindingAdapter({"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"})
public static void setListener(View view, final OnViewDetachedFromWindow detach,
        final OnViewAttachedToWindow attach) {
    if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) {
        final OnAttachStateChangeListener newListener;
        if (detach == null && attach == null) {
            newListener = null;
        } else {
            newListener = new OnAttachStateChangeListener() {
                @Override
                public void onViewAttachedToWindow(View v) {
                    if (attach != null) {
                        attach.onViewAttachedToWindow(v);
                    }
                }

                @Override
                public void onViewDetachedFromWindow(View v) {
                    if (detach != null) {
                        detach.onViewDetachedFromWindow(v);
                    }
                }
            };
        }
        final OnAttachStateChangeListener oldListener = ListenerUtil.trackListener(view,
                newListener, R.id.onAttachStateChangeListener);
        if (oldListener != null) {
            view.removeOnAttachStateChangeListener(oldListener);
        }
        if (newListener != null) {
            view.addOnAttachStateChangeListener(newListener);
        }
    }
}
  • The above example is slightly more complicated than normal because View uses add and remove for the listener instead of a set method for View.OnAttachStateChangeListener. The android.databinding.adapters.ListenerUtil class helps keep track of the previous listeners so that they may be removed in the Binding Adaper.

  • 以上的例子比通常的例子要稍微複雜。由於View對監聽器使用add和remove去替換一個View。OnAttachStateChangeListener的set方法。android.databinding.adapters.ListenerUtil類幫助跟蹤以前的簡體器一遍監聽器能夠在Binding Adapter中移除。

  • By annotating the interfaces OnViewDetachedFromWindow and OnViewAttachedToWindow with @TargetApi(VERSION_CODES.HONEYCOMB_MR1), the data binding code generator knows that the listener should only be generated when running on Honeycomb MR1 and new devices, the same version supported by addOnAttachStateChangeListener(View.OnAttachStateChangeListener).

  • OnViewDetachedFromWindow和OnViewAttachedToWindsw接口經過使用註解@TaegetApi(VERSION_CODES.HONEYCOMEB_MR1),只有當運行在Honeycomb MR1盒心得設備時,數據綁定代碼生產者纔會生成監聽器。

#Converters 轉換器

###Object Conversions 對象轉換器

  • When an Object is returned from a binding expression, a setter will be chosen from the automatic, renamed, and custom setters. The Object will be cast to a parameter type of the chosen setter.

  • 當從一個綁定表達式中返回一個對象,該對象的一個自動的、從命名的河自定義的setters將被選擇。該對象的類型將被轉換成被選擇的setter的參數類型。

  • This is a convenience for those using ObservableMaps to hold data. for example:

  • 使用ObservableMaps去控制數據的這是很方便的,例如:

<TextView
   android:text='@{userMap["lastName"]}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
  • The userMap returns an Object and that Object will be automatically cast to parameter type found in the setter setText(CharSequence). When there may be confusion about the parameter type, the developer will need to cast in the expression.
  • userMap返回一個對象而且該對象將被自動轉換成在setText(CharSequence)方法中找到的參數類型。當參數類型可能被混淆的時候,開發者獎須要去轉換表達式。

###Custom Conversions 自定義轉換器

  • Sometimes conversions should be automatic between specific types. For example, when setting the background:
  • 一些時候的轉換器應該自動選擇特定的類型。例如,當設置背景時:
<View
   android:background="@{isError ? @color/red : @color/white}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
  • Here, the background takes a Drawable, but the color is an integer. Whenever a Drawable is expected and an integer is returned, the int should be converted to a ColorDrawable. This conversion is done using a static method with a BindingConversion annotation:
  • 這裏,北京得到了一個Drawable,可是顏色是一個整型。不管是一個Drawable異常仍是返回一個整型,該整型都應該被轉換成一個ColorDrawable。使用一個使用了BindingConversion註解的靜態方法完成了轉換。
@BindingConversion
public static ColorDrawable convertColorToDrawable(int color) {
   return new ColorDrawable(color);
}
  • Note that conversions only happen at the setter level, so it is not allowed to mix types like this:
  • 注意,轉換旨在setter方法裏觸發,因此轉換不容許像下面這樣的混合類型。
<View
   android:background="@{isError ? @drawable/error : @color/white}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

###Android Studio Support for Data Binding Android Studio對於數據綁定的支持。

Android Studio supports many of the code editing features for data binding code. For example, it supports the following features for data binding expressions:

Android Studio支持不少語句數據綁定代碼的代碼編輯特性。例如,它支持對於數據綁定表達式的一下特性:

  • Syntax highlighting
  • 語法高亮
  • Flagging of expression language syntax errors
  • XML code completion
  • References, including navigation (such as navigate to a declaration) and quick documentation

Note: Arrays and a generic type, such as the Observable class, might display errors when there are no errors. 注意:Arrays和通常的類型,例如Observable類沒有錯誤的時候可能會顯示錯誤。

  • The Preview pane displays default values for data binding expressions if provided. In the following example excerpt of an element from a layout XML file, the Preview pane displays the PLACEHOLDER default text value in the TextView.
  • 若是支持的話,預覽版對於數據綁定表達式會展現默認的值。如下例子類子引用自一個來自於佈局xml文件的元素,預覽版會顯示TextView的 PLACEHOLDER的迷人值
<TextView android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@{user.firstName, default=PLACEHOLDER}"/>
  • If you need to display a default value during the design phase of your project, you can also use tools attributes instead of default expression values, as described in Designtime Layout Attributes.
  • 在設計你的項目的時候,若是你須要去現實一個默認值,雖然在設計時的佈局屬性中描述了,你也可使用tools屬性替換默認的表達式值,
相關文章
相關標籤/搜索