(一百八十九)Android Jetpack 学习(二)- 数据绑定库

(一百八十九)Android Jetpack 学习(一)

继续学习Android Jetpack其他组件

 

目录

数据绑定库

使用数据绑定库

使用入门

Build environment

Android Studio support for data binding

Additional resources

布局和绑定表达式

Layouts and binding expressions

Data object

Binding data

Expression language

Null coalescing operator

Property Reference

Avoiding null pointer exceptions

Collections

Resources

Event handling

Method references

Listener bindings

Imports, variables, and includes

Imports

Variables

Includes

Additional resources

Samples

Codelabs

Blog posts

Work with observable data objects


 

数据绑定库

学习https://developer.android.google.cn/topic/libraries/data-binding/

数据绑定库是一种支持库,借助该库,您可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源。

布局通常是使用调用界面框架方法的代码在 Activity 中定义的。例如,下面的代码会调用 findViewById() 以查找 TextView 微件,并将其绑定到 viewModel 变量的 userName 属性:

KotlinJava

    TextView textView = findViewById(R.id.sample_text);
    textView.setText(viewModel.getUserName());

    

以下示例展示了如何在布局文件中使用数据绑定库将文本直接分配到微件。这样就无需调用上述任何 Java 代码。请注意在赋值表达式中使用 @{} 语法:

<TextView
        android:text="@{viewmodel.userName}" />
    

借助布局文件中的绑定组件,您可以移除 Activity 中的许多界面框架调用,使其维护起来更简单、方便。还可以提高应用性能,并且有助于防止内存泄漏以及避免空指针异常。

这样做很大的好处是代码里不会有一堆findViewById并且还要加以区分的进行数据初始化,直接放在布局里就完成了

 

使用数据绑定库

要了解如何在 Android 应用中使用数据绑定库,请参阅以下页面。

使用入门

了解如何准备开发环境以使用数据绑定库,包括支持 Android Studio 中的数据绑定代码。

点击进入使用入门:https://developer.android.google.cn/topic/libraries/data-binding/start.html

 

使用入门

Learn how to get your development environment ready to work with the Data Binding Library, including support for data binding code in Android Studio.

The Data Binding Library offers both flexibility and broad compatibility—it's a support library, so you can use it with devices running Android 4.0 (API level 14) or higher.

It's recommended to use the latest Android Plugin for Gradle in your project. However, data binding is supported on version 1.5.0 and higher. For more information, see how to update the Android Plugin for Gradle.

大概说了下支持数据绑定的环境

 

Build environment

To get started with data binding, download the library from the Support Repository in the Android SDK manager. For more information, see Update the IDE and SDK Tools.

To configure your app to use data binding, add the dataBinding element to your build.gradle file in the app module, as shown in the following example:

android {
    ...
    dataBinding {
        enabled = true
    }
}

Note: You must configure data binding for app modules that depend on libraries that use data binding, even if the app module doesn't directly use data binding.

 

Android Studio support for data binding

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

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

Caution: Arrays and a generic type, such as the Observable class, might incorrectly display errors.

The Preview pane in Layout Editor displays the default value of data binding expressions, if provided. For example, the Preview pane displays the my_default value on the TextView widget declared in the following example:

<TextView android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.firstName, default=my_default}"/>

If you need to display a default value only during the design phase of your project, you can use tools attributes instead of default expression values, as described in Tools Attributes Reference.

https://developer.android.google.cn/studio/write/tool-attributes.html

上面这个链接里有很多tools属性使用

比如

tools:targetApi

适用于:任何元素

使用者:Lint

此属性的工作方式与 Java 代码中的 @TargetApi 注解相同:通过它,您可以指定支持相应元素的 API 级别(指定为整数或代号)。

它会告知工具您认为该元素(及任何子元素)将只能在指定的 API 级别或更高级别中使用。这样,如果该元素或其属性在您指定为 minSdkVersion 的 API 级别中不可用,Lint 将不会向您发出警告。

例如,GridLayout 只能在 API 级别 14 及更高级别中使用,但您知道此布局不会用于任何更低版本,在这种情况下,您就可以使用此属性:

<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        tools:targetApi="14" >
    

但是,您应该使用支持库中的 GridLayout

 

Additional resources

To learn more about data binding, consult the following additional resources.

Samples

Codelabs

Blog posts

 

布局和绑定表达式

借助表达式语言,您可以编写将变量关联到布局中的视图的表达式。数据绑定库会自动生成将布局中的视图与您的数据对象绑定所需的类。该库提供了可在布局中使用的导入、变量和头文件等功能。

该库的这些功能可与您的现有布局无缝地共存。例如,可以在表达式中使用的绑定变量是在 data 元素中定义的,而该元素是界面布局的根元素的同级项。这两个元素都包含在 layout 标记中,如以下示例所示:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto">
        <data>
            <variable
                name="viewmodel"
                type="com.myapp.data.ViewModel" />
        </data>
        <ConstraintLayout... /> <!-- UI layout's root element -->
    </layout>

点击进入 https://developer.android.google.cn/topic/libraries/data-binding/expressions.html

 

Layouts and binding expressions

The expression language allows you to write expressions that handle events dispatched by the views. The Data Binding Library automatically generates the classes required to bind the views in the layout with your data objects.

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. The following code shows a sample layout file:

<?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 text is set to the firstName property of the user variable:

<TextView android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{user.firstName}" />

Note: Layout expressions should be kept small and simple, as they can't be unit tested and have limited IDE support. In order to simplify layout expressions, you can use custom binding adapters.

讲了下大概怎么使用,声明一个data节点,然后里面有个类似于类的声明,后面布局就直接可以用这个类的局部变量初始化了。

 

Data object

Let's assume for now that you have a plain-old object to describe the User entity:

KotlinJava

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 an object that follows a set of conventions, such as the usage of accessor methods in Java, as shown in the following example:

KotlinJava

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 android:text attribute accesses the firstName field in the former class and the getFirstName() method in the latter class. Alternatively, it is also resolved to firstName() if that method exists.

大概讲了下布局里的使用等效于get方法,并且说了是对于变量只读一次并且以后再也不会变的。但如果我后面调用set方法重新初始化是不是就不行了呢?没环境好烦。。后面看来好像就用数据初始化了一下

 

Binding data

A binding class is generated for each layout file. By default, the name of the class is based on the name of the layout file, converting it to Pascal case and adding the Binding suffix to it. The above layout filename is activity_main.xml so the corresponding generated class is ActivityMainBinding. This class holds all the bindings from the layout properties (for example, the user variable) to the layout's views and knows how to assign values for the binding expressions.The recommended method to create the bindings is to do it while inflating the layout, as shown in the following example:

KotlinJava

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
   User user = new User("Test", "User");
   binding.setUser(user);
}

At runtime, the app displays the Test user in the UI. Alternatively, you can get the view using a LayoutInflater, as shown in the following example:

KotlinJava

ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());

If you are using data binding items inside a Fragment, ListView, or RecyclerView adapter, you may prefer to use the inflate() methods of the bindings classes or the DataBindingUtil class, as shown in the following code example:

KotlinJava

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

初始化布局中使用到的data

 

Expression language

Common features

The expression language looks a lot like expressions found in managed code. You can use the following operators and keywords in the expression language:

  • Mathematical + - / * %
  • String concatenation +
  • Logical && ||
  • Binary & | ^
  • Unary + - ! ~
  • Shift >> >>> <<
  • Comparison == > < >= <= (Note that < needs to be escaped as &lt;)
  • 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}'

 

大概列举了一下常见的操作符也适用于data binding

 

Null coalescing operator

The null coalescing operator (??) chooses the left operand if it isn't null or the right if the former is null.

android:text="@{user.displayName ?? user.lastName}"

This is functionally equivalent to:

android:text="@{user.displayName != null ? user.displayName : user.lastName}"

讲了下??的用法等效于 != null ?

 

Property Reference

An expression can reference a property in a class by using the following format, which is the same for fields, getters, and ObservableField objects:

android:text="@{user.lastName}"

这个属性调用之前看过了

 

Avoiding null pointer exceptions

Generated data binding code automatically checks for null values and avoid null pointer exceptions. For example, in the expression @{user.name}, if user is null, user.name is assigned its default value of null. If you reference user.age, where age is of type int, then data binding uses the default value of 0.

这个空指针自动处理好评

 

Collections

Common collections, such as arrays, lists, sparse lists, and maps, can 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>"/>
    <variable name="sparse" type="SparseArray&lt;String>"/>
    <variable name="map" type="Map&lt;String, String>"/>
    <variable name="index" type="int"/>
    <variable name="key" type="String"/>
</data>
…
android:text="@{list[index]}"
…
android:text="@{sparse[index]}"
…
android:text="@{map[key]}"

Note: For the XML to be syntactically correct, you have to escape the < characters. For example: instead of List<String> you have to write List&lt;String>.

You can also refer to a value in the map using the object.key notation. For example, @{map[key]} in the example above can be replaced with @{map.key}.

集合的使用和代码里一样,就是[]加index,也提及 @{map[key]}等效于 @{map.key}

其中要注意<要替换为&lt;来避免xml的语法错误

 

String literals

You can use single quotes to surround the attribute value, which allows you to use double quotes in the expression, as shown in the following example:

android:text='@{map["firstName"]}'

It is also possible to use double quotes to surround the attribute value. When doing so, string literals should be surrounded with back quotes `:

android:text="@{map[`firstName`]}"

单双引号要分别扩attribute和string literals,以区分属性和字符串

 

Resources

You can access resources in an expression by using the following 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, as shown in the following table:

TypeNormal referenceExpression reference
String[]@array@stringArray
int[]@array@intArray
TypedArray@array@typedArray
Animator@animator@animator
StateListAnimator@animator@stateListAnimator
color int@color@color
ColorStateList@color@colorStateList

这边资源使用不是很看得懂。。。上手试比较靠谱

 

Event handling

Data binding allows you to write expression handling events that are dispatched from the views (for example, the onClick() method). Event attribute names are determined by the name of the listener method with a few exceptions. For example, View.OnClickListener has a method onClick(), so the attribute for this event is android:onClick.

There are some specialized event handlers for the click event that need an attribute other than android:onClick to avoid a conflict. You can use the following attributes to avoid these type of conflicts:

ClassListener setterAttribute
SearchViewsetOnSearchClickListener(View.OnClickListener)android:onSearchClick
ZoomControlssetOnZoomInClickListener(View.OnClickListener)android:onZoomIn
ZoomControlssetOnZoomOutClickListener(View.OnClickListener)android:onZoomOut

You can use the following mechanisms to handle an event:

  • 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 doesn't create a listener and sets a null listener instead.
  • 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.

 

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 doesn't exist or its signature is incorrect, you receive a compile time error.

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, consider the following example layout data object:

KotlinJava

public class MyHandlers {
    public void onClickFriend(View view) { ... }
}

The binding expression can assign the click listener for a view to the onClickFriend() method, as follows:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="handlers" type="com.example.MyHandlers"/>
       <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: 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.

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, consider the following presenter class that has the onSaveClick() method:

KotlinJava

public class Presenter {
    public void onSaveClick(Task task){}
}

Then you can bind the click event to the onSaveClick() method, 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>

When a callback is used in an expression, data binding automatically creates the necessary listener and registers it for the event. When the view fires the event, data binding evaluates the given expression. As in regular binding expressions, you still get null and thread safety of data binding while these listener expressions are being evaluated.

In the example above, we haven't defined the view parameter that is passed to onClick(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 follows:

android:onClick="@{(view) -> presenter.onSaveClick(task)}"

Or if you want to use the parameter in the expression, it could work as follows:

KotlinJava

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:

KotlinJava

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 isn't 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 a boolean.

KotlinJava

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 value for that type. For example, null for reference types, 0 for int, false for boolean, etc.

If you need to use an expression with a predicate (for example, ternary), you can use void as a symbol.

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 maintain. 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.

主要区别

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.

即method references在数据绑定的时候就创建了,而listener binding是在event除法的时候才执行。

 

Imports, variables, and includes

The Data Binding Library provides features such as imports, variables, and includes. Imports make easy to reference classes inside your layout files. Variables allow you to describe a property that can be used in binding expressions. Includes let you reuse complex layouts across your app.

Imports

Imports allow you to easily reference classes inside your layout file, just like in managed code. Zero or more import elements may be used inside the data element. The following code example imports the View class to the layout file:

<data>
    <import type="android.view.View"/>
</data>

Importing the View class allows you to reference it from your binding expressions. The following example shows how to reference the VISIBLE and GONE constants of the View class:

<TextView
   android:text="@{user.lastName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>

Type aliases

When there are class name conflicts, one of the classes may be renamed to an alias. The following example renames the View class in the com.example.real.estate package to Vista:

<import type="android.view.View"/>
<import type="com.example.real.estate.View"
        alias="Vista"/>

You can use Vista to reference the com.example.real.estate.View and View may be used to reference android.view.View within the layout file.

Import other classes

Imported types can be used as type references in variables and expressions. The following example shows User and List used as the type of a variable:

<data>
    <import type="com.example.User"/>
    <import type="java.util.List"/>
    <variable name="user" type="User"/>
    <variable name="userList" type="List&lt;User>"/>
</data>

Caution: Android Studio doesn't yet handle imports so the autocomplete for imported variables may not work in your IDE. Your app still compiles and you can work around the IDE issue by using fully qualified names in your variable definitions.

You can also use the imported types to cast part of an expression. The following example casts the connection property to a type of User:

<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. The following code imports the MyStringUtils class and references its capitalize method:

<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 managed code, java.lang.* is imported automatically.

Variables

You can use multiple variable elements 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. The following example declares the user, image, and note variables:

<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 doesn't implement the Observable interface, the variables are not observed.

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

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

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

Includes

Variables may be passed into an included layout's binding from the containing layout by using the app namespace and the variable name in an attribute. The following example shows included user variables from the name.xml and contact.xml layout files:

<?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>

Data binding doesn't support include as a direct child of a merge element. For example, the following layout isn't supported:

<?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><!-- Doesn't work -->
       <include layout="@layout/name"
           bind:user="@{user}"/>
       <include layout="@layout/contact"
           bind:user="@{user}"/>
   </merge>
</layout>

 

 

大概说来就是可以在布局中用部分代码中的用法

 

 

Additional resources

To learn more about data binding, consult the following additional resources.

Samples

Codelabs

Blog posts

 

Work with observable data objects

Observability refers to the capability of an object to notify others about changes in its data. The Data Binding Library allows you to make objects, fields, or collections observable.

Any plain-old object can be used for data binding, but modifying the object doesn't automatically cause the UI to update. Data binding can be used to give your data objects the ability to notify other objects, known as listeners, when its data changes. There are three different types of observable classes: objects, fields, and collections.

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

大概有个adaper和notifychange的作用,当数据改变时会自动刷新

 

 

Observable fields

Some work is involved in creating classes that implement the Observable interface, which could not be worth the effort if your classes only have a few properties. In this case, you can use the generic Observable class and the following primitive-specific classes to make fields observable:

Observable fields are self-contained observable objects that have a single field. The primitive versions avoid boxing and unboxing during access operations. To use this mechanism, create a public final property in the Java programming language or a read-only property in Kotlin, as shown in the following example:

KotlinJava

private static class User {
    public final ObservableField<String> firstName = new ObservableField<>();
    public final ObservableField<String> lastName = new ObservableField<>();
    public final ObservableInt age = new ObservableInt();
}

To access the field value, use the set() and get() accessor methods, as follows:

KotlinJava

user.firstName.set("Google");
int age = user.age.get();

Note: Android Studio 3.1 and higher allow you to replace observable fields with LiveData objects, which provide additional benefits to your app. For more information, see Use LiveData to notify the UI about data changes.

有些已经封装好的类可以直接用,它们会让Ui随便数据变化自动刷新

 

Observable collections

Some apps use dynamic structures to hold data. Observable collections allow access to these structures by using a key. The ObservableArrayMap class is useful when the key is a reference type, such as String, as shown in the following example:

KotlinJava

ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);

In the layout, the map can be found using the string keys, as follows:

<data>
    <import type="android.databinding.ObservableMap"/>
    <variable name="user" type="ObservableMap<String, Object>"/>
</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"/>

The ObservableArrayList class is useful when the key is an integer, as follows:

KotlinJava

ObservableArrayList<Object> user = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add(17);

In the layout, the list can be accessed through the indexes, as shown in the following example:

<data>
    <import type="android.databinding.ObservableList"/>
    <import type="com.example.my.app.Fields"/>
    <variable name="user" type="ObservableList<Object>"/>
</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"/>

集合的用法

 

Observable objects

A class that implements the Observable interface allows the registration of listeners that want to be notified of property changes of on the observable object.

The Observable interface has a mechanism to add and remove listeners, but you must decide when notifications are sent. To make development easier, the Data Binding Library provides the BaseObservable class, which implements the listener registration mechanism. The data class that implements BaseObservable is responsible for notifying when the properties change. This is done by assigning a Bindable annotation to the getter and calling the notifyPropertyChanged() method in the setter, as shown in the following example:

KotlinJava

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);
    }
}

Data binding generates a class named BR in the module package which contains the IDs of the resources used for data binding. The Bindable annotation generates an entry in the BR class file during compilation. If the base class for data classes cannot be changed, the Observable interface can be implemented using a PropertyChangeRegistry object to register and notify listeners efficiently.

大概介绍了下怎么写一个可观察的对象,当数据改变时会通知ui改变

 

Additional resources

To learn more about data binding, consult the following additional resources.

Samples

Codelabs

Blog posts

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值