android 数据绑定(1)Ativity、Fragment、Item绑定数据源

1.简介

官方文档:

   https://developer.android.com/topic/libraries/data-binding

官方示例:

  https://github.com/android/databinding-samples

作用:

  把layout 与 数据对象关联,将layout上的组件与对象的成员绑定.让layout上的组件的值来自数据对象。如:

    <TextView android:text="@{data.value}" />

2.简单用法:绑定Activity与数据源

2.1 打开绑定选项

  只能在主module的 build.gradle 中打开,即使主module代码没有使用数据绑定,而他依赖的module使用了数据绑定,也要在主module中打开。

1     buildFeatures{
2         dataBinding true
3         // for view binding :
4         // viewBinding true
5     }

2.2 布局 activity_main.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <layout xmlns:android="http://schemas.android.com/apk/res/android">
 3     <data>
 4         <variable name="data" type="com.example.databind.Data" />      <!--声明的对象data-->
 5         <variable name="click" type="com.example.databind.Click" />
 6     </data>
 7     <androidx.constraintlayout.widget.ConstraintLayout >
 8 
 9         <TextView android:text="@{data.value, default = value}" />      <!--值来自数据对象data-->
10         <Button android:onClick="@{() -> click.onStartClick(data)}" />
11 
12     </androidx.constraintlayout.widget.ConstraintLayout>
13 </layout>

其中

  • 跟元素<layout> 包含 元素 <data>和 跟布局<ConstraintLayout >
  • <data>元素用来定义layout使用的数据源,可以使用稍微复杂语法,如<import ...>,见第4、5行。
  • layout上的组件使用@{数据源名.成员}指定值,@{}内可以使用简单的的绑定表达式,如第10行。

2.3 数据对象 Data.java

 1 package com.example.databind;
 2 
 3 public class Data {
 4     public String   key;
 5     public int      value;
 6 
 7     public Data(String key, int value){
 8         this.key = key;
 9         this.value = value;
10     }
11 
12     @Override
13     public String toString() {
14         return "key = " + key + " value = " + value;
15     }
16 }

2.4 建立绑定关系

 1 package com.example.databind;
 2 import android.os.Bundle;
 3 import androidx.appcompat.app.AppCompatActivity;
 4 import androidx.databinding.DataBindingUtil;
 5 
 6 import com.example.databind.databinding.ActivityMainBinding;
 7 
 8 public class MainActivity extends AppCompatActivity {
 9 
10     private ActivityMainBinding binding;
11     private Data                data;
12 
13     private void init(){
14         data = new Data("time", 10);
15         binding = DataBindingUtil.setContentView(MainActivity.this, R.layout.activity_main);
16         binding.setData(data);
17         binding.setClick(new Click(binding));
18     }
19 
20     @Override
21     protected void onCreate(Bundle savedInstanceState) {
22         super.onCreate(savedInstanceState);
23         setContentView(R.layout.activity_main);
24         init();
25     }
26 }

 关于其中的 ActivityMainBinding :

  • 第15行得到了把一个activity和一个布局关联,得到一个绑定对象 ActivityMainBinding,它是绑定框架生成的,见5
  • 写完layout后 Rebuild Project 一下 就可以生成它。

3. 绑定Fragment与数据源 

常用的方法:

  • DataBindingUtil.inflate(inflater, R.layout.daily_data, container, false) 
  • DataBindingUtil.bind(root) ,返回可能为空的绑定对象。
 1     lateinit var binding : DailyDataBinding
 2 
 3     override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?
 4         ): View? {
 5         binding = DataBindingUtil.inflate(inflater, R.layout.daily_data, container, false)
 6 
 7         binding.dailyShare.setOnClickListener(this::onShareClicked)
 8         //...   
 9         return binding.root
10     }

  或者

1     var binding : DailyBinding? = null
2     fun initBinding(root : View){
3         binding = DataBindingUtil.bind(root)
4         binding?.page = page
5         binding?.start = startTime
6         //...          
7     }

3.1 布局文件

  1 <?xml version="1.0" encoding="utf-8"?>
  2 <layout xmlns:app="http://schemas.android.com/apk/res-auto"
  3     xmlns:android="http://schemas.android.com/apk/res/android">
  4     <data >
  5         <variable name="data" type="com.example.databind.Data" />
  6         <variable name="click" type="com.example.databind.Click" />
  7     </data>
  8 
  9     <androidx.constraintlayout.widget.ConstraintLayout
 10         android:layout_width="match_parent"
 11         android:layout_height="match_parent"
 12         android:clickable="true"
 13         >
 14         <TextView
 15             android:id="@+id/title"
 16             android:layout_width="wrap_content"
 17             android:layout_height="wrap_content"
 18             android:layout_marginTop="16dp"
 19             android:text="Hello Data Binding !"
 20             app:layout_constraintLeft_toLeftOf="parent"
 21             app:layout_constraintRight_toRightOf="parent"
 22             app:layout_constraintTop_toTopOf="parent" />
 23 
 24         <TextView
 25             android:id="@+id/key"
 26             android:layout_width="wrap_content"
 27             android:layout_height="wrap_content"
 28             android:layout_marginTop="16dp"
 29             android:text="@{data.key, default = key}"
 30             app:layout_constraintStart_toStartOf="parent"
 31             app:layout_constraintEnd_toStartOf="@+id/value"
 32             app:layout_constraintTop_toBottomOf="@+id/title"
 33             app:layout_constraintHorizontal_chainStyle="packed"
 34             />
 35 
 36         <TextView
 37             android:id="@+id/value"
 38             android:layout_width="wrap_content"
 39             android:layout_height="wrap_content"
 40             android:layout_marginStart="16dp"
 41             android:layout_marginLeft="16dp"
 42             android:text="@{String.valueOf(data.value),default = value}"
 43             app:layout_constraintEnd_toEndOf="parent"
 44             app:layout_constraintStart_toEndOf="@+id/key"
 45             app:layout_constraintTop_toTopOf="@+id/key" />
 46 
 47         <Button
 48             android:id="@+id/start"
 49             android:layout_width="wrap_content"
 50             android:layout_height="wrap_content"
 51             android:layout_marginTop="16dp"
 52             android:onClick="@{() -> click.onStartClick(data)}"
 53             android:text="start"
 54             android:textAllCaps="false"
 55             app:layout_constraintEnd_toStartOf="@+id/stop"
 56             app:layout_constraintHorizontal_chainStyle="packed"
 57             app:layout_constraintStart_toStartOf="parent"
 58             app:layout_constraintTop_toBottomOf="@+id/key" />
 59 
 60         <Button
 61             android:id="@+id/stop"
 62             android:layout_width="wrap_content"
 63             android:layout_height="wrap_content"
 64             android:layout_marginStart="16dp"
 65             android:layout_marginLeft="16dp"
 66             android:onClick="@{() -> click.onStopClicked(data)}"
 67             android:text="stop"
 68             android:textAllCaps="false"
 69             app:layout_constraintBottom_toBottomOf="@+id/start"
 70             app:layout_constraintEnd_toStartOf="@+id/reset"
 71             app:layout_constraintStart_toEndOf="@+id/start"
 72             app:layout_constraintTop_toTopOf="@+id/start" />
 73 
 74         <Button
 75             android:id="@+id/reset"
 76             android:layout_width="wrap_content"
 77             android:layout_height="wrap_content"
 78             android:layout_marginStart="16dp"
 79             android:layout_marginLeft="16dp"
 80             android:text="reset"
 81             android:textAllCaps="false"
 82             app:layout_constraintBottom_toBottomOf="@+id/start"
 83             app:layout_constraintEnd_toEndOf="parent"
 84             app:layout_constraintStart_toEndOf="@+id/stop"
 85             app:layout_constraintTop_toTopOf="@+id/start"
 86             app:layout_constraintVertical_bias="1.0" />
 87 
 88         <Button
 89             android:id="@+id/list_fragment"
 90             android:layout_width="wrap_content"
 91             android:layout_height="wrap_content"
 92             android:layout_marginTop="32dp"
 93             android:text="list fragment"
 94             android:textAllCaps="false"
 95             app:layout_constraintEnd_toEndOf="parent"
 96             app:layout_constraintStart_toStartOf="parent"
 97             app:layout_constraintTop_toBottomOf="@+id/stop" />
 98 
 99         <EditText
100             android:id="@+id/editText"
101             android:layout_width="wrap_content"
102             android:layout_height="wrap_content"
103             android:layout_marginTop="32dp"
104             android:ems="10"
105             android:inputType="textPersonName"
106             android:text="Name"
107             app:layout_constraintEnd_toEndOf="@+id/list_fragment"
108             app:layout_constraintStart_toStartOf="@+id/list_fragment"
109             app:layout_constraintTop_toBottomOf="@+id/list_fragment" />
110 
111     </androidx.constraintlayout.widget.ConstraintLayout>
112 
113 </layout>

3.2 数据类

Data.java

 1 package com.example.databind;
 2 
 3 public class Data {
 4     public String   key;
 5     public int      value;
 6 
 7     public Data(String key, int value){
 8         this.key = key;
 9         this.value = value;
10     }
11 
12     @Override
13     public String toString() {
14         return "key = " + key + " value = " + value;
15     }
16 }

click.java

 1 package com.example.databind;
 2 import android.util.Log;
 3 import androidx.databinding.ViewDataBinding;
 4 import java.util.Timer;
 5 import java.util.TimerTask;
 6 
 7 public class Click {
 8     ViewDataBinding     binding;
 9     private Timer       timer;
10 
11     public void onStartClick(final Data data){
12         timer = new Timer();
13         timer.schedule(new TimerTask() {
14             @Override
15             public void run() {
16                 if (--data.value  < 0){
17                     cancel();
18                     return;
19                 }
20                 Log.e("ActivityMainBinding","data : " + data);
21                 data.key = "left";
22 //                binding.setData(data);
23 //                binding.notifyChange();
24 //                binding.notifyPropertyChanged(R.id.value);
25 //                binding.value.invalidate();
26                 if (!binding.hasPendingBindings()){
27                     binding.invalidateAll();
28                 }
29             }
30         },1000 * 1,1000 * 1);
31     }
32     public void onStopClicked(Data data){
33         cancel();
34     }
35     private void cancel(){
36         if (timer != null){
37             timer.cancel();
38             timer = null;
39         }
40     }
41     public Click(ViewDataBinding binding){
42         this.binding = binding;
43     }
44 }

3.3 绑定

 1 package com.example.databind;
 2 
 3 import android.os.Bundle;
 4 import android.view.LayoutInflater;
 5 import android.view.View;
 6 import android.view.ViewGroup;
 7 
 8 import androidx.annotation.NonNull;
 9 import androidx.annotation.Nullable;
10 import androidx.databinding.DataBindingUtil;
11 import androidx.databinding.ViewDataBinding;
12 import androidx.fragment.app.Fragment;
13 
14 import butterknife.ButterKnife;
15 import butterknife.OnClick;
16 
17 public class MainFrgmt extends Fragment {
18 
19     ViewDataBinding             binding;
20     private Data                data;
21 
22     private void init(){
23         data = new Data("time", 10);
24         binding.setVariable(BR.data,data);
25         binding.setVariable(BR.click,new Click(binding));
26     }
27     @Nullable
28     @Override
29     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
30         binding = DataBindingUtil.inflate(inflater,R.layout.frgmt_main,container,false);
31         View view = binding.getRoot();
32         ButterKnife.bind(this,view);
33         init();
34         return view;
35     }
36 
37     @OnClick(R.id.reset)
38     public void onResetClicked(View view){
39         data.key = "time";
40         data.value = 10;
41         binding.invalidateAll();
42     }
43 }

 其中:

  • 第31行创建绑定对象 binding
  • 第24、25行设置绑定的数据对象,其中的BR是绑定库生成的一个类,其中包含<data>中声明的变量的id。如data的id就是BR.data
  • 第41行更新数据对象

4.Item绑定数据源

4.1 item布局 

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <layout xmlns:app="http://schemas.android.com/apk/res-auto"
 3     xmlns:android="http://schemas.android.com/apk/res/android">
 4 
 5     <data>
 6         <variable name="item" type="com.example.databind.list.ItemData" />
 7     </data>
 8 
 9     <LinearLayout
10         android:orientation="horizontal"
11         android:layout_width="match_parent"
12         android:layout_height="wrap_content"
13         >
14         <ImageView
15             android:id="@+id/item_icon"
16             android:layout_width="wrap_content"
17             android:layout_height="wrap_content"
18             android:layout_marginLeft="16dp"
19             android:layout_marginStart="16dp"
20             android:layout_marginTop="8dp"
21             android:layout_marginBottom="8dp"
22             android:layout_gravity="center_vertical"
23             android:layout_weight="1"
24             app:imageSrc="@{item.icon}" />
25         <TextView
26             android:id="@+id/item_title"
27             android:layout_width="wrap_content"
28             android:layout_height="wrap_content"
29             android:layout_weight="5"
30             android:layout_marginLeft="32dp"
31             android:layout_marginStart="32dp"
32             android:layout_marginRight="8dp"
33             android:layout_marginEnd="8dp"
34             android:layout_gravity="center_vertical"
35             android:gravity="left|center_vertical"
36             android:textAllCaps="false"
37             android:textSize="16sp"
38             android:layout_marginTop="8dp"
39             android:layout_marginBottom="8dp"
40             android:text="@{item.title,default = item}" />
41     </LinearLayout>
42 
43 </layout>

4.2 数据类

1 package com.example.databind.list;
2 
3 public class ItemData {
4     public String   title;
5     public int      icon;
6 }

4.3 adapter

 1 package com.example.databind.list;
 2 
 3 import android.view.LayoutInflater;
 4 import android.view.View;
 5 import android.view.ViewGroup;
 6 import android.widget.ImageView;
 7 
 8 import androidx.annotation.NonNull;
 9 import androidx.databinding.BindingAdapter;
10 import androidx.databinding.DataBindingUtil;
11 import androidx.recyclerview.widget.RecyclerView;
12 
13 import com.example.databind.R;
14 import com.example.databind.databinding.ListItemBinding;
15 
16 import java.util.ArrayList;
17 import java.util.List;
18 
19 public class ListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
20 
21     private List<ItemData>  datas = new ArrayList<>();
22 
23     public void initData(){
24         for (int i = 0 ; i < 32; ++i){
25             ItemData item = new ItemData();
26             item.title = "item" + i;
27             switch (i){
28                 case 11: case 21:    case 31:
29                 case 1 : item.icon = R.mipmap.icon1;    break;
30 
31                 case 12: case 22:    case 32:
32                 case 2 : item.icon = R.mipmap.icon2;    break;
33 
34                 case 13: case 23:    case 33:
35                 case 3 : item.icon = R.mipmap.icon3;    break;
36 
37                 case 14: case 24:    case 34:
38                 case 4 : item.icon = R.mipmap.icon4;    break;
39 
40                 case 15: case 25:    case 35:
41                 case 5 : item.icon = R.mipmap.icon5;    break;
42 
43                 case 16: case 26:
44                 case 6 : item.icon = R.mipmap.icon6;    break;
45 
46                 case 17: case 27:
47                 case 7 : item.icon = R.mipmap.icon7;    break;
48 
49                 case 18: case 28:
50                 case 8 : item.icon = R.mipmap.icon8;    break;
51 
52                 case 19: case 29:
53                 case 9 : item.icon = R.mipmap.icon9;    break;
54                 default: item.icon = R.mipmap.icon0;    break;
55             }
56             datas.add(item);
57         }
58     }
59     
60     @BindingAdapter({"imageSrc"})
61     public static void setImage(ImageView view, int icon){
62         view.setImageResource(icon);
63     }
64 
65     @NonNull
66     @Override
67     public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
68         LayoutInflater inflater = LayoutInflater.from(parent.getContext());
69         View view = inflater.inflate(R.layout.list_item,parent,false);
70         BindHolder holder = new BindHolder(view);
71 
72         return holder;
73     }
74 
75     @Override
76     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
77         BindHolder bh = (BindHolder) holder;
78         ItemData item = datas.get(position);
79         ListItemBinding binding = DataBindingUtil.bind(bh.itemView);
80         binding.setItem(item);
81     }
82 
83     @Override
84     public int getItemCount() {
85         return datas.size();
86     }
87 
88 
89     public static class BindHolder extends RecyclerView.ViewHolder{
90 
91         public BindHolder(@NonNull View itemView) {
92             super(itemView);
93         }
94     }
95 }

5.ActivityMainBinding 等绑定类哪来的?

5.1 他们是绑定框架生成的接口

位置:

 以 Frgmt1Binding 为例,它的实现在 : appuildgeneratedap_generated_sourcesdebugoutcomexampledatabinddatabinding 目录下,

  comexampledatabind  是包名,如下:

默认的命名规则:

  布局文件名按Pascal命名方法(忽略下划线_) + Binding , 如布局文件是 Frgmt1.xml 那么生成的类就是 Frgmt1Binding

5.4 修改生成的绑定类的名字

 1 <layout xmlns:app="http://schemas.android.com/apk/res-auto"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     xmlns:android="http://schemas.android.com/apk/res/android">
 4     <data class="AAAAAAA">
 5         <import type="android.view.View" />
 6         <import type="com.example.databind.Exts" />
 7     </data>
 8     <androidx.constraintlayout.widget.ConstraintLayout
 9         android:clickable="true"
10         android:background="#ffffff"
11         android:layout_width="match_parent"
12         android:layout_height="match_parent">
13 ...

  这个示例 在当前模块的 databinding 包中生成绑定类  AAAAAAA 

1     <data class=".BBBBBB">
2 3     </data>

  这个示例 在模块包中生成绑定类  BBBBBB

1     <data class="com.example.CCC">
2 3     </data>

  这个 示例在 com.example 包中创建绑定类 CCC

5.3 代码

  1 package com.example.databind.databinding;
  2 import com.example.databind.R;
  3 import com.example.databind.BR;
  4 import androidx.annotation.NonNull;
  5 import androidx.annotation.Nullable;
  6 import android.view.View;
  7 @SuppressWarnings("unchecked")
  8 public class Frgmt1BindingImpl extends Frgmt1Binding  {
  9 
 10     @Nullable
 11     private static final androidx.databinding.ViewDataBinding.IncludedLayouts sIncludes;
 12     @Nullable
 13     private static final android.util.SparseIntArray sViewsWithIds;
 14     static {
 15         sIncludes = null;
 16         sViewsWithIds = new android.util.SparseIntArray();
 17         sViewsWithIds.put(R.id.imageView, 3);
 18         sViewsWithIds.put(R.id.textView, 4);
 19     }
 20     // views
 21     @NonNull
 22     private final androidx.constraintlayout.widget.ConstraintLayout mboundView0;
 23     // variables
 24     // values
 25     // listeners
 26     // Inverse Binding Event Handlers
 27 
 28     public Frgmt1BindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
 29         this(bindingComponent, root, mapBindings(bindingComponent, root, 5, sIncludes, sViewsWithIds));
 30     }
 31     private Frgmt1BindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
 32         super(bindingComponent, root, 0
 33             , (android.widget.ImageView) bindings[3]
 34             , (android.widget.TextView) bindings[1]
 35             , (android.widget.TextView) bindings[4]
 36             , (android.widget.TextView) bindings[2]
 37             );
 38         this.key.setTag(null);
 39         this.mboundView0 = (androidx.constraintlayout.widget.ConstraintLayout) bindings[0];
 40         this.mboundView0.setTag(null);
 41         this.value.setTag(null);
 42         setRootTag(root);
 43         // listeners
 44         invalidateAll();
 45     }
 46 
 47     @Override
 48     public void invalidateAll() {
 49         synchronized(this) {
 50                 mDirtyFlags = 0x4L;
 51         }
 52         requestRebind();
 53     }
 54 
 55     @Override
 56     public boolean hasPendingBindings() {
 57         synchronized(this) {
 58             if (mDirtyFlags != 0) {
 59                 return true;
 60             }
 61         }
 62         return false;
 63     }
 64 
 65     @Override
 66     public boolean setVariable(int variableId, @Nullable Object variable)  {
 67         boolean variableSet = true;
 68         if (BR.click == variableId) {
 69             setClick((com.example.databind.Click) variable);
 70         }
 71         else if (BR.data == variableId) {
 72             setData((com.example.databind.Data) variable);
 73         }
 74         else {
 75             variableSet = false;
 76         }
 77             return variableSet;
 78     }
 79 
 80     public void setClick(@Nullable com.example.databind.Click Click) {
 81         this.mClick = Click;
 82     }
 83     public void setData(@Nullable com.example.databind.Data Data) {
 84         this.mData = Data;
 85         synchronized(this) {
 86             mDirtyFlags |= 0x2L;
 87         }
 88         notifyPropertyChanged(BR.data);
 89         super.requestRebind();
 90     }
 91 
 92     @Override
 93     protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
 94         switch (localFieldId) {
 95         }
 96         return false;
 97     }
 98 
 99     @Override
100     protected void executeBindings() {
101         long dirtyFlags = 0;
102         synchronized(this) {
103             dirtyFlags = mDirtyFlags;
104             mDirtyFlags = 0;
105         }
106         java.lang.String stringValueOfDataValue = null;
107         java.lang.String dataKey = null;
108         com.example.databind.Data data = mData;
109         int dataValue = 0;
110 
111         if ((dirtyFlags & 0x6L) != 0) {
112 
113 
114 
115                 if (data != null) {
116                     // read data.key
117                     dataKey = data.key;
118                     // read data.value
119                     dataValue = data.value;
120                 }
121 
122 
123                 // read String.valueOf(data.value)
124                 stringValueOfDataValue = java.lang.String.valueOf(dataValue);
125         }
126         // batch finished
127         if ((dirtyFlags & 0x6L) != 0) {
128             // api target 1
129 
130             androidx.databinding.adapters.TextViewBindingAdapter.setText(this.key, dataKey);
131             androidx.databinding.adapters.TextViewBindingAdapter.setText(this.value, stringValueOfDataValue);
132         }
133     }
134     // Listener Stub Implementations
135     // callback impls
136     // dirty flag
137     private  long mDirtyFlags = 0xffffffffffffffffL;
138     /* flag mapping
139         flag 0 (0x1L): click
140         flag 1 (0x2L): data
141         flag 2 (0x3L): null
142     flag mapping end*/
143     //end
144 }

5.4 可以直接使用 ViewDataBinding

1     private ViewDataBinding binding;
2 
3     private void init(View view){
4         binding = DataBindingUtil.bind(view);
5         MainActivity main = (MainActivity) getActivity();
6         binding.setVariable(BR.data,main.data);
7     }

 

原文地址:https://www.cnblogs.com/mhbs/p/11621078.html