Data Binding Library数据绑定框架
Data Binding Library是Google在2015年IO大會上發布的一個用于實現MVVM設計模式的支持庫
環境配置
在Android Studio 2.0 原生支持Data Binding框架,配置也變得很簡單,只需要在gradle中配置如下腳本即可
android {dataBinding{enabled = true;} }布局文件
使用Data Binding后,布局文件也跟以前的有所區別
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"><data><import type="android.view.View"/><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>| layout | 布局文件的根節點 |
| data | 要實現 MVVM 的 ViewModel 就需要把數據(Model)與 UI(View) 進行綁定,data 節點的作用就像一個橋梁,搭建了 View 和 Model 之間的通路 |
| variable | 聲明變量 |
| import | 導包 |
| @{ } | 使用定義的變量 |
注意:java.lang.* 包中的類會被自動導入,可以直接使用,例如要定義一個 String 類型的變量:
Includes
<?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不支持include標簽作為merge標簽的直接子標簽,例如下面的布局是不支持的
<?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>綁定數據
@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); }- 系統會幫我們自動生成一個以xml布局文件名字開始,以Binding結束的類,例如上面的MainActivityBinding.java,另外還會生成一個BR文件,類似于R文件。
- 除了使用框架自動生成的 MainActivityBinding,我們也可以通過如下方式自定義類名
use data binding items inside a ListView adapter
1、BaseAdapter
class CommonAdapter<T> extends BaseAdapter{private List<T> mList;private Context mContext;private int layoutId;private int variableId;public CommonAdapter(List<T> list, Context context, int lauoutId, int variableId) {mList = list;mContext = context;this.layoutId = lauoutId;this.variableId = variableId;}@Overridepublic int getCount() {return mList.size();}@Overridepublic Object getItem(int position) {return mList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewDataBinding binding = null;if (convertView == null){binding = DataBindingUtil.inflate(LayoutInflater.from(mContext),layoutId,parent,false);}else {binding = DataBindingUtil.getBinding(convertView);}binding.setVariable(variableId,mList.get(position));return binding.getRoot();}}2、布局文件
ListView的item布局
3、邏輯代碼
LayoutLvBinding binding = DataBindingUtil.setContentView(this, R.layout.layout_lv);List<User> list = new ArrayList<>();CommonAdapter<User> adapter = new CommonAdapter<>(list,this,R.layout.lv_item, com.google.demo.BR.user);binding.setAdapter(adapter);Observable Objects
private static class User extends BaseObservable {private String firstName;private String lastName;@Bindablepublic String getFirstName() {return this.firstName;}@Bindablepublic 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);} }- BaseObservable:實現數據的更新同步到UI控件上需要實現該接口
- @Bindable注解標記過 的getter 方法會在 BR 中生成一個 entry
- notifyPropertyChanged(BR.firstName)通知View更新
ObservableFields
private static class User {public final ObservableField<String> firstName =new ObservableField<>();public final ObservableField<String> lastName =new ObservableField<>();public final ObservableInt age = new ObservableInt(); }ObservableField, ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, and ObservableParcelable
Observable Collections
ObservableArrayMap
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>(); user.put("firstName", "Google"); user.put("lastName", "Inc."); user.put("age", 17);在布局文件中使用
<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"/>ObservableArrayList
ObservableArrayList<Object> user = new ObservableArrayList<>(); user.add("Google"); user.add("Inc."); user.add(17);在布局文件中使用
<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"/>生成Binding class
所生成的Binding類都繼承自ViewDataBinding
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater); MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false); MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot); ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater, layoutId,parent, attachToParent); ViewDataBinding binding = DataBindingUtil.bind(viewRoot, layoutId);綁定事件
public class MyHandlers {public void onClickFriend(View view) { ... }public void onClickEnemy(View 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="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.lastName}"android:onClick="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/></LinearLayout> </layout>使用資源數據
android:padding="@{large? (int)@dimen/largePadding : (int)@dimen/smallPadding}"Null Coalescing Operator
android:text="@{user.displayName ?? user.lastName}"等價于
android:text="@{user.displayName != null ? user.displayName : user.lastName}"集合的使用
<data><import type="android.util.SparseArray"/><import type="java.util.Map"/><import type="java.util.List"/><variable name="list" type="List<String>"/><variable name="sparse" type="SparseArray<String>"/><variable name="map" type="Map<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]}"Custom Setters
@BindingAdapter({"imageUrl"}) public static void loadImage(ImageView iv,String url){if (url == null){iv.setImageResource(R.mipmap.ic_launcher);}else {Glide.with(iv.getContext()).load(url).into(iv);}}Converters(轉換器)
@BindingConversion public static ColorDrawable convertColorToDrawable(int color) {return new ColorDrawable(color); } <View android:background="@{isError ? @drawable/error : @color/white}"android:layout_width="wrap_content"android:layout_height="wrap_content"/>DataBindingComponent
所有被注解@BindingAdapter標記的方法,如果該方法為非靜態方法,那么都需要一個Component對象,而所需要的Component對象由DataBindingComponent提供,所以我們需要自定義類實現DataBindingComponent接口
public class Utils {@BindingAdapter({"imageUrl"})public static void loadImage(ImageView iv,String url){if (url == null){iv.setImageResource(R.mipmap.ic_launcher);}else {Glide.with(iv.getContext()).load(url).into(iv);}} } public class MyComponent implements android.databinding.DataBindingComponent {private Utils mUtils@Overridepublic Utils getUtils() {if (mUtils == null){mUtils = new Utils();}return mUtils;}}在DataBindingUtil.setContentView()之前設置Component
DataBindingUtil.setDefaultComponent(new MyComponent());參考
https://github.com/LyndonChin/MasteringAndroidDataBinding
總結
以上是生活随笔為你收集整理的Data Binding Library数据绑定框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RxJava 教程第一部分:入门之 生命
- 下一篇: MVC,MVP,MVVM设计模式的比较