我們絕對不會花費任何多余的時間和體力在無意義的事情上,因為我們的眼睛永遠只盯著獵物 ————《狼道》
目錄
前言
一、簡介
二、基本配置
三、簡單使用
四、Demo簡介
五、基礎用法
六、語法
七、插件支持
八、Demo地址
九、參考文檔
十、內容推薦
前言
剛認識DataBinding的時候是在MVVM模式上看到的,之前一直都是在使用MVP模式。之后想換個MVVM模式試試,看是否和別人說的一樣比MVP好用,簡潔。但是剛接觸就遇到一個砍(DataBinding),然后就猶如你看到的一樣,有了這篇文章。這篇文章主要是介紹了DataBinding基礎用法,對DataBinding有一個粗略的了解。也是為我后面學習MVVM模式做個鋪墊吧,文章如有不足,請多多指教。好了,廢話不多說,接招吧!!

一、簡介
早在2015谷歌 I/O大會上,介紹了一個新的框架DataBinding,從名字就可以看出來,這是一個數(shù)據綁定庫。借助該庫,您可以使用聲明性格式(而非程序化地)將布局中的界面組件綁定到應用中的數(shù)據源
那么問題來了:
(1)數(shù)據綁定是什么?
將一個用戶界面元素(控件)的屬性綁定到一個類型(對象)實例上的某個屬性的方法
簡而言之,把代碼中的數(shù)據和xml(UI)綁定起來,雙方都能對數(shù)據進行操作,并且在數(shù)據發(fā)生變化的時候,自動刷新數(shù)據。
(2)數(shù)據綁定有什么用?
數(shù)據綁定分為單向綁定和雙向綁定兩種方式
單向綁定就是說數(shù)據的流向是單方面的,只能從代碼流向UI;
雙向綁定的數(shù)據流向是雙向的,當業(yè)務代碼中的數(shù)據改變時,UI上的數(shù)據能夠得到刷新;當用戶通過UI交互編輯了數(shù)據時,數(shù)據的變化也能自動的更新到業(yè)務代碼中的數(shù)據上。
而DataBinding就是實現(xiàn)數(shù)據綁定的一個框架
(3)DataBinding有什么用?
- 把代碼中的數(shù)據和xml(UI)綁定起來,雙方都能對數(shù)據進行操作,并且在數(shù)據發(fā)生變化的時候,自動刷新數(shù)據
- 借助布局文件中的綁定組件,您可以移除 Activity 中的許多界面框架調用,使其維護起來更簡單、方便。還可以提高應用性能,并且有助于防止內存泄漏以及避免空指針異常
(4)優(yōu)點
- 您可以移除 Activity 中的許多界面框架調用,使其維護起來更簡單、方便
- 提高應用性能,并且有助于防止內存泄漏以及避免空指針異常
- 減少大量重復的代碼,去除Activity/Fragment中的UI代碼
了解DataBinding是什么后,我們就可以開始搬磚了。
二、基本配置
1、環(huán)境要求:
- 系統(tǒng)版本:Android 2.1(API level 7)及以上
- Gradle版本:1.5.0-alpha1及以上
- Android Studio版本:1.3及以上
2、app要使用Data Binding,需要添加Data Binding到gradle構建文件里
App module - build.gradle
android {
...
dataBinding{
enabled = true
}
}
這樣就可以在項目中使用
三、簡單使用
步驟:
(1)在布局中最外部套一層layout標簽
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name" />
</android.support.constraint.ConstraintLayout>
</layout>
(2)關聯(lián)布局
//綁定布局 替代setContentView(R.layout.activity_main);
ActivityMainBinding bind = DataBindingUtil.setContentView(this,R.layout.activity_main);
//給指定id賦值
bind.btn.setText("xxxxx");
這樣算是綁定完成。是不是比butterknife更簡潔.. 當然不只這些。
這里以一個Demo,看看DataBinding常用的幾種方式。
四、Demo簡介
1、效果圖:
2、主頁布局activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!--定義點擊事件-->
<data>
<variable
name="click"
type="android.view.View.OnClickListener"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/et_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:gravity="center"
android:layout_weight="1"
android:inputType="text"
android:hint="聯(lián)系名字?" />
<EditText
android:id="@+id/et_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:gravity="center"
android:inputType="number"
android:layout_weight="1"
android:hint="聯(lián)系號碼?"
/>
<!--點擊事件設置-->
<Button
android:id="@+id/btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{click}"
android:text="添加聯(lián)系人"
/>
</LinearLayout>
<!--聯(lián)系人列表-->
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</layout>
3、MainActivity.class
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
ActivityMainBinding bind;
private List<User> list=new ArrayList<>();
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//關聯(lián)布局
bind= DataBindingUtil.setContentView(this,R.layout.activity_main);
//設置點擊事件
bind.setClick(this);
//recycler適配
LinearLayoutManager manager = new LinearLayoutManager(this);
bind.recycler.setLayoutManager(manager);
myAdapter = new MyAdapter(this,list);
bind.recycler.setAdapter(myAdapter);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_add:
User user = new User();
user.setName(bind.etName.getText().toString());
user.setPhone(bind.etPhone.getText().toString());
user.setImgUrl("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1545725899676&di=f875404bfb91dc586cf14030097b7a35&imgtype=0&src=http%3A%2F%2Fimg1.gtimg.com%2Fzj%2Fpics%2Fhv1%2F112%2F112%2F2259%2F146920147.jpg");
list.add(user);
myAdapter.notifyItemInserted(list.size());
break;
}
}
}
4、User.class
public class User {
private String name;//姓名
private String phone;//電話
private String imgUrl;//頭像
public String getImgUrl() { return imgUrl; }
public void setImgUrl(String imgUrl) { this.imgUrl = imgUrl; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
}
5、適配器布局adapter_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<data>
<!--定義在布局中使用的數(shù)據-->
<variable
name="user"
type="lwb.blcs.databinding.User"/>
<!--定義點擊事件-->
<variable
name="click"
type="lwb.blcs.databinding.MyOnClickListen"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<!--給控件賦值單向綁定@{} 雙向綁定@={}-->
<!-- 給點擊事件傳值user.name -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:onClick="@{()->click.onClickName(user.name)}"
android:layout_weight="1"
android:text="@={user.name}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:onClick="@{()->click.onClickPhone(user.phone)}"
android:text="@={user.phone}" />
<!-- 設置點擊事件-->
<!-- 設置自定義圖片屬性 imageUrl-->
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="10dp"
android:layout_weight="1"
android:onClick="@{click.onClickImage}"
app:imageUrl="@{user.imgUrl}"
/>
</LinearLayout>
</layout>
6、適配器MyAdapter.class
class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private MainActivity mainActivity;
private List<User> list;
private final LayoutInflater inflater;
public MyAdapter(MainActivity mainActivity, List<User> list) {
this.mainActivity = mainActivity;
this.list = list;
inflater = LayoutInflater.from(mainActivity);
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
//MyAdapter適配器綁定布局
AdapterMainBinding bind = DataBindingUtil.inflate(inflater, R.layout.adapter_main, viewGroup, false);
return new MyViewHolder(bind);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int i) {
//綁定數(shù)據
holder.bind.setUser(list.get(i));
//設置點擊事件
holder.bind.setClick(new MyOnClickListen(mainActivity));
}
@Override
public int getItemCount() {
return list.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
//ViewHolder 構造函數(shù)修改
AdapterMainBinding bind;
public MyViewHolder(@NonNull AdapterMainBinding itemView) {
//itemView.getRoot()獲取View
super(itemView.getRoot());
this.bind=itemView;
}
}
}
7、ImageUtils.class
/**
* 1.加載圖片,無需手動調用此方法
* 2.使用@BindingAdapter注解設置自定義屬性的名稱,imageUrl就是屬性的名稱,
* 當ImageView中使用imageUrl屬性時,會自動調用loadImage方法,
*/
@BindingAdapter({"imageUrl"})
public static void loadImage(ImageView imageView, String url) {
Glide.with(imageView.getContext())
.load(url)
.into(imageView);
}
8、MyOnClickListen.class
public class MyOnClickListen {
private Activity mainActivity;
public MyOnClickListen(Activity mainActivity) {
this.mainActivity = mainActivity;
}
//方法引用
public void onClickName(String name){
Toast.makeText(mainActivity,name,Toast.LENGTH_SHORT).show();
}
//方法引用
public void onClickPhone(String phone){
Toast.makeText(mainActivity,phone,Toast.LENGTH_SHORT).show();
}
//監(jiān)聽器綁定
public void onClickImage(View view){
Toast.makeText(mainActivity,"圖片",Toast.LENGTH_SHORT).show();
}
}
9、基礎信息
//相關依賴
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.github.bumptech.glide:glide:4.8.0'
//網絡權限
<uses-permission android:name="android.permission.INTERNET"/>
簡單Demo就完成,省了大量的findViewById(),當然布局的使用也有點不習慣。不過相對代碼簡潔了很多。
不過在寫demo過程中也到過更新不及時,無法等到對象的情況。需Clean Project
五、基礎用法
當然Databinding用法還有很多,上面demo只是簡單嘗試。更多使用需要查看官網API
(1)bind UI
<data>
<variable
name="user"
type="lwb.blcs.databinding.User" />
</data>
//activity_main布局外層添加layout標簽后自動生成ActivityMainBinding
ActivityMainBinding bind = DataBindingUtil.setContentView(this,R.layout.activity_main);
User user = new User("張si", "12");
//布局variable 定義屬性name 則代碼中可綁定數(shù)據
//綁定數(shù)據的第一種用法
//bind.setVariable(BR.user,user);
//綁定數(shù)據的第二種用法
bind.setUser(user);
(2) bind 點擊事件
1.常用方法:
<data>
<variable
name="click"
type="android.view.View.OnClickListener"/>
</data>
<Button
android:id="@+id/btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{click}"
android:text="添加聯(lián)系人"
/>
//關聯(lián)布局
ActivityMainBinding bind = DataBindingUtil.setContentView(this,R.layout.activity_main);
//綁定點擊事件
bind.setClick(this);
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_add:
....
break;
}
}
2.方法引用
<data>
<variable
name="click"
type="lwb.blcs.databinding.MainActivity.MyOnClickListen" />
</data>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{click.onClickAge}"
android:layout_marginTop="20dp"
android:text="@{user.age}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{()->click.onClickText(user)}"
android:text="@{user.name}" />
ActivityMainBinding bind = DataBindingUtil.setContentView(this,R.layout.activity_main);
bind.setClick(new MyOnClickListen());
//點擊事件處理
public class MyOnClickListen{
//方法引用
public void onClickAge(View view){
Toast.makeText(MainActivity.this,"點我onClickAge",Toast.LENGTH_SHORT).show();
}
//監(jiān)聽器綁定
public void onClickText(User user){
Toast.makeText(MainActivity.this,user.name,Toast.LENGTH_SHORT).show();
}
}
(3) 圖片顯示
1、BindingAdapter注解設置自定義屬性
/**
* 1.加載圖片,無需手動調用此方法
* 2.使用@BindingAdapter注解設置自定義屬性的名稱,imageUrl就是屬性的名稱,
* 當ImageView中使用imageUrl屬性時,會自動調用loadImage方法,
*/
@BindingAdapter({"imageUrl"})
public static void loadImage(ImageView imageView, String url) {
Glide.with(imageView.getContext()).load(url)
.error(R.mipmap.error)
.into(imageView);
}
<!-- 當imageUrl屬性存在時,會自動調用ImageHelper的loadImage方法 -->
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:scaleType="centerCrop"
app:imageUrl="@{user.picUrl}" />
六、語法
(1)variable | Import
在data標簽下可以使用多個import標簽和variable標簽:
- variable 標簽是約定數(shù)據的引用對象:語法為 <variable name="變量名" type="類型"/>
- import 標簽是引入數(shù)據類型:語法為 <import type="類型"/>
<data>
<import type="android.view.View"/>
<import type="java.util.List"/>
<!--這里小于號和大于號 需要用轉義字符-->
<variable name="userList" type="List<String>"/>
<variable name="user" type="lwb.blcs.databinding.User"/>
</data>
<TextView
android:text="@{userList[0]}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{user.isShow ? View.VISIBLE : View.GONE}"/>
(2)設置別名alias
路徑不同,但名稱相同的類,可以借助于別名來解決,別名借助alias字段來標識:語法:<import type="類型" alias="別名">
<import type="lwb.blcs.databinding.User" />
<import type="lwb.blcs.databinding.bean.User" alias="UserBean"/>
<variable
name="user"
type="User"/>
<variable
name="user"
type="UserBean"/>
(3)自定義Binding類名稱
在默認情況下,綁定類根據布局文件的名稱生成,命名規(guī)則:布局名首字母,去掉下劃線,下劃線后的首字母大寫 ,并加上后綴 Binding。該類放在 databinding模塊包下的包中。例:activiy_main.xml ==> ActivityMainBinding
我們可以通過調整
data元素的class屬性,將 binding 類進行重命名或放置在不同的包中
//會放在默認生成的databinding包中
<data class="ActMain">
......
</data>
//在包名中生成bind類
<data class=".ActMainBind">
......
</data>
//為生成binding類指定路徑 使用完整的包名稱
<data class="lwb.blcs.databinding.ActMainBinding">
......
</data>
//默認生成的Binding類
ActivityMainBinding bind= DataBindingUtil.setContentView(this,R.layout.activity_main);
//自定義后生成的Binding類
ActMain bind= DataBindingUtil.setContentView(this,R.layout.activity_main);
(4)Observable
Observable classes provide a way in which data bound UI can be notified of changes.
譯為:提供了一種可以向數(shù)據綁定UI通知更改的方法
Data Binding綁定UI后更改數(shù)據并不能更新到UI。所以Data Binding提供了Observable來自動更新數(shù)據。
Observable分為三類:
- Observable objects
- Observable fields
- Observable collections
主要作用:當數(shù)據發(fā)生改變的時候,可以及時更新UI。
1、Observable objects
Observable是一個java接口,DataBinding基于此接口提供了一個基礎類BaseObserable
public class User extends BaseObservable{
private String name;
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
}
步驟:
(1)繼承BaseObserable
(2)getter添加Bindable注解
(3)setter方法中使用notifyPropertyChanged提醒UI更新數(shù)據
2、Observable fields
一個對象包裝器,使其可觀察??梢允褂每捎^察的字段類自動更新該字段;
public class User {
public ObservableField<String> name = new ObservableField<>();
}
//使用方法
User user = new User();
user.name.set("更新");
當然ObservableField<T>中傳入的泛型可以是Java中的基本類型;還可以使用 ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, ObservableParcelable等具體的類型,效果和ObservableField<T>一樣。
3、Observable collections
顧名思義:可觀察的集合,當數(shù)據發(fā)生變化時可以及時通知UI更新。
使用方式有兩種:
ObservableArrayList
ObservableArrayMap
<data>
<import type="android.databinding.ObservableMap" />
<import type="android.databinding.ObservableList" />
<variable
name="map"
type="ObservableMap<String, String>" />
<variable
name="list"
type="ObservableList<String>" />
</data>
ObservableArrayMap<String, String> map = new ObservableArrayMap<>();
ObservableArrayList<String> list= new ObservableArrayList<>();
(5)綁定表達式語言中可以使用以下運算符和關鍵字
算數(shù) + - / * %
字符串拼接 +
邏輯 && ||
位 & | ^
一元 + - ! ~
移位 >> >>> <<
關系 == > < >= <=
instanceof
組 ( )
字面量 - 字符,字符串,數(shù)字,null
方法調用
字段訪問
數(shù)組訪問 [ ]
三元操作 ? :
表達式語法不支持以下操作:
this
super
new顯式泛型調用
<T>
(6)轉義字符
簡單的用法就寫到這了 就不長篇大論了 能堅持看到這的說明還沒被我催眠0.0
原理這里也不分析了,太長看起來也累。
有興趣的可以看我寫的《Android ButterKnife入門到放棄》的原理分析,就會發(fā)現(xiàn)兩者有點類似
七、插件支持
https://plugins.jetbrains.com/plugin/9271-databinding-support
使布局轉化更加簡單
八、Demo地址
https://github.com/DayorNight/DataBinding
九、參考文檔
https://developer.android.google.cn/topic/libraries/data-binding/?hl=zh_cn
https://www.imooc.com/learn/719
十、內容推薦
《CSDN》
《Android ButterKnife入門到放棄》???????
《Android 下載安裝應用APK封裝(適配8.0)》
《Android Notification通知簡單封裝(適配8.0)???????》???????
《Android 10文檔閱讀總結》
若您發(fā)現(xiàn)文章中存在錯誤或不足的地方,希望您能指出!
