Android:DataBinding的一二事
Android:DataBinding的一二事
寫在前面
最近冷靜了一個星期,學了大名鼎鼎的DataBinding。導師說這跟H5一樣,是未來Android發展的趨勢。看了一下,確實是Google官方跟著MVVM一起推出來的,所以就學了相關的知識,個別也運用到項目中。
不過講心里話,不知道是不是平時的findViewById用習慣了,還是ButterKnife太好用了,一直覺得用這樣的方式去綁定數據有點渾身不得勁,先學著吧。
所以今天來分享一下學習DataBinding過程。不過不同的是,在這里我不介紹它的使用規范或者方法,因為目前網上關于DataBinding的優秀文章很多很多,文末也會有相關鏈接。
只不過由于大部分文章都是針對Gradle1.5版本去寫的,有些方法和注意事項已經不適用了,而且文章幾乎只分開介紹了基本使用,并沒有介紹開發中的一些實際問題,我在學的過程中也踩了不少坑,所以本篇文章主要先介紹一下新版本的不同(坑),然后用一個小的實戰項目來具體展示如何使用DataBinding。
站在前人的肩膀上,幫后人踩坑
初始配置
第一次使用的時候需要注意,Gradle版本需要大于1.5。如果大于1.5, 只需要在當前 Module 下的 build.gradle 文件中添加如下代碼即可 :
android {
...
dataBinding {
enabled true
}
...
}
注意,只需要在 android{ } 里面加省略號之間的三行就行了,其他啥都不用配置。在這里,我項目用的版本是 Gradle 2.1.3 。
使用注意事項
1、 android:text 中只能寫” @{…}”的形式
在其他優秀DataBinding使用教程,我們學會了像下面這樣的使用規范:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.age}" />
但是千萬不能這樣寫:
<TextView
...
android:text="年齡@{user.age}" />
<TextView
...
android:text="年齡+@{user.age}" /></code></pre>
對比一下吧,沒有對比就沒有傷害:

當然如果你這樣寫的話:
<TextView
...
android:text="@{年齡user.age}" />
<TextView
...
android:text="@{年齡+user.age}" /></code></pre>
壓根編譯都過不去,請珍惜生命,善待自己。
2、注意 android:text 中是 String 類型
假如上面的 user.age 是 int 類型的話,一定要記得轉成 String 類型,怎么轉?當然是 String.valueOf() 了:
<TextView
...
android:text="@{String.valueOf(user.age)}" />
3、引用資源Bug已經被解決
在之前所有的文章中,都有提到 官方有個bug ,說在引用資源時必須加上 int 才能通過編譯。
但是經過我的測試,不加也是可以編譯且正常運行的,可能這個bug已經被解決掉了:
<!--不同間距-->
<TextView
...
android:text="@{person.name}"
android:paddingLeft="@{person.isTrue ? @dimen/largeDP : @dimen/smallDP}"/>
<!--不同字號-->
<TextView
...
android:text="@{person.phone}"
android:textSize="@{large ? @dimen/largeSP : @dimen/smallSP}" /></code></pre>
從下圖可以看到,第一個行間距不同,第二行字號不同:

4、include不能添加在非根結點的ViewGroup中?
同樣的,在之前幾乎所有的教程中,說 include 標簽不能非根結點的 ViewGroup 中,說程序會Crash掉,但是經過我的測試,程序也能正常編譯運行,估計也是一個Bug吧:
<!--根結點-->
<LinearLayout
...
android:orientation="vertical">
<include
layout="@layout/layout_text"
bind:user="@{user}" />
<include
layout="@layout/layout_button"
bind:btClick="@{btClick}" />
<!-- 非根節點 ViewGroup 仍然有效-->
<LinearLayout
...
android:orientation="vertical">
<include
layout="@layout/layout_text"
bind:user="@{user}" />
<include
layout="@layout/layout_button"
bind:btClick="@{btClick}" />
</LinearLayout>
</LinearLayout></code></pre>
如下圖,布局是一樣的:

以上兩個Bug問題是僅在 有限測試 后得出的結論,如有錯誤請指正,謝謝!
5、使用資源或者屬性時,記得引包
什么意思呢,比如下面根據 large 的值引用不同資源/屬性:
<!--顯示-->
<TextView
...
android:visibility="@{large ? View.INVISIBLE : View.VISIBLE}"/>
<!--顏色-->
<TextView
...
android:textColor="@{large ? Color.RED : Color.YELLOW}"/></code></pre>
這個時候,我們用到了 View 包和 Color 包,所以必須在 data 標簽中 import 這兩個包,才能顯示正常:
<import type="android.view.View" />
<import type="android.graphics.Color"/>
從下圖可以看到第一行沒有顯示,第二行是紅色的:

6、自定義綁定類名稱注意包名
一般來說,編譯器會給我們自動生成一個綁定類,類名與布局文件的名稱一致。有些時候,我們需要自己自定義:
<import class="**.CustomBinding" />
需要注意的是,這里 CustomBinding 之前的 * 號部分必須是項目的包名,那包名需要一直寫到哪呢?
這個沒有具體規定,比如我項目的目錄是這樣的:
|--com
|--dataBinding
|--adapter
|--bean
|--pojo
|--ui
|--utils
我可以寫 com.databinding.CustomBinding 也可以寫 com.databinding.ui.CustomBinding ,只要在項目包中即可。當然了,不能只寫個 com.CustomBinding ,這是個細節問題,大家注意一下就好。
7、XML文件中不能包含< >符號
實際上這是個很有趣的問題,開始我還沒有發現,先看下面這段代碼:
<!--數據層-->
<data>
<import type="android.databinding.ObservableMap" />
<variable
name="muser"
type="ObservableMap<String, Object>" />
</data>
這里的 variable 類型為一個 ObservableMap ,既然是 Map 當然就有 Key 和 Value ,這里是 String 類型的 Key ,Object 類型的 Value ,但是注意這里并不是你看錯了,就是這么寫的。因為這里不允許使用 “< >” 這樣的格式,否則會直接報錯。
8、IDE的各種問題
因為DataBinding推出不是很久,用的人不是很多,聽說在早前的AS版本中,IDE是沒有智能提示的。但是現在的IDE已經對DataBinding有了很好的支持了,但是仍然還是有很多小的問題。
比如在XML文件的UI層的根結點中,一些常用的屬性沒法提示,連 width 和 height 有時候都打不出來,但是如果真的手打出來的話,仍然是有效的,估計是IDE的問題。
同樣的,有時候在Activity中想要得到綁定類的時候,總是提示沒有這個類,但是綁定命名卻跟XML文件命名一致的,這個時候我們只要把XML文件名稱隨便重命名一下就行了,估計也是IDE沒有反應過來。
常見問題
1、xx missing it
Error:Execution failed for task ':DataBindingDemo:compileDebugJavaWithJavac'.
> java.lang.RuntimeException: Found data binding errors.
****/ data binding error ****msg:Identifiers must have user defined types from the XML file. Color is missing it
file:D:\Android\AndroidProject\Android5.0Demo\DataBindingDemo\src\main\res\layout\activity_resource.xml
loc:120:45 - 120:49
****\ data binding error ****
這個問題很常見,不過跟我上面說的第五點是一致的,大部分都是因為沒有導包的原因,所以找不到這個 Color 。
解決辦法就是一句話,什么Missing導什么。
2、Could not find method XX
這也是個細節性問題了,比如下面這段代碼(有省略):
<variable
name="btclick"
type="android.view.View.OnClickListener" />
...
<!--點擊事件-->
<Button
...
android:onClick="btclick" /></code></pre>
這里就是給按鈕定義一個監聽,一般我們寫 android:onClick 的時候直接寫方法名就可以了,但是這里如果我們直接寫的話,能編譯通過,但是一點擊就會Crash,錯誤如下:
java.lang.IllegalStateException: Could not find method btclick(View) in a parent or ancestor Context for android:onClick attribute defined on view class android.support.v7.widget.AppCompatButton
提示說沒有找到方法,解決辦法就是 android:onClick=”@{btclick}” ,沒什么好解釋的,細心細心。
3、NullPoint怎么辦
這個問題也很有趣,剛接觸DataBinding的時候,我也有相同的疑問,但是實際上,DataBinding不會出現NollPoint,至少在已經綁定的對象上不會出現。
為什么呢?下面這是 Data Binding(數據綁定)用戶指南 給出的解釋:
“Data Binding代碼生成時自動檢查是否為nulls來避免出現null pointer exceptions錯誤。例如,在表達式@{user.name}中,如果user是null,user.name會賦予它的默認值(null)。如果你引用user.age,age是int類型,那么它的默認值是0。”
可以看到,DataBinding已經給我們處理好了,所以不用擔心這個問題。
4、編譯出錯,控制臺一大串錯誤信息怎么辦
在編譯過程中,如果有錯,控制臺會打印一大串問題,這個時候只需要看錯誤信息的最后一條就行了。
而且一般來說,關鍵性錯誤信息都是下面這樣的格式:
****/ data binding error ****
msg:...
file:...
****\ data binding error ****
舉個栗子
好了,大概了解了DataBinding的使用方式,現在來用一個小小的例子來說具體如何在項目中使用它。
關于下面的例子很簡單,但是有幾點說明:
- 只說DataBinding相關部分;
- 特地選用了比較復雜的RecyclerView;
- 特地在item中添加圖片和文字,圖片來源為Url;
- 重點在于RecyclerView的動態綁定。
先來看一下item中的布局吧,也是精簡了一部分:
<layout
xmlns:android="
</layout></code></pre>
可以看到,這里只有TextView使用了DataBinding,圖片并沒有設置,讓我們來看看在復雜的布局中如何使用動態綁定。
因為是一個列表數據,item是復用的,所以沒辦法直接綁定,那么就給ViewHolder綁定。
直接上源碼吧,難度不大:
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.NewsViewHolder> {
private List<NewsBean> list;
private Context context;
public NewsAdapter(Context context, List<NewsBean> list) {
this.list = list;
this.context = context;
}
@Override
public NewsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_news, parent, false);
return new NewsViewHolder(itemView);
}
@Override
public void onBindViewHolder(NewsViewHolder holder, int position) {
//給ViewHolder綁定
holder.bind(list.get(position));
//加載圖片
Picasso.with(context).load(list.get(position).getPicUrl()).into(holder.itemPicImage);
}
@Override
public int getItemCount() {
return list.size();
}
public class NewsViewHolder extends RecyclerView.ViewHolder {
//綁定類
private ItemNewsBinding inBinding;
private ImageView itemPicImage;
public NewsViewHolder(View itemView) {
super(itemView);
//為每一個item設置
inBinding = DataBindingUtil.bind(itemView);
itemPicImage = (ImageView) itemView.findViewById(R.id.iv_item_pic);
}
/**
* 綁定方法
*
* @param news Bean對象
*/
public void bind(@NonNull NewsBean news) {
inBinding.setNews(news);
}
}</code></pre>
如果你仔細看了上面的代碼,你會發現其實只是多了三件事情:
- ViewHolder中創建綁定類;
- 利用綁定類設置相關內容;
- 綁定ViewHolder的時候綁定上相關內容。
就這么多,來看看效果圖吧:

其實例子本身很簡單,但是想說的不是例子本身。從代碼中我們可以發現,圖片的加載并沒有使用DataBinding,而是用Picasso直接加載。當然也可以使用DataBinding的靜態方法去直接展示,但是感覺有點怪怪的。而且如果這個item的布局十分復雜,考慮的情況很多的話,這種情況顯然很麻煩很麻煩。何況這里還沒有考慮點擊事件。
所以總的來說就是,不熟悉就慎用慎用。
總結
因為是剛接觸,對這種數據綁定的方式各種不適應,而且很多方法可能暫時不知道,就像上面復雜的布局不知道有沒有更簡單的方法去處理。反正給我的感覺就是有點麻煩,也不準備繼續深入學習DataBinding了。
優點
- 節省了給View設置Id的工作;
- 節省了findViewById的工作;
- 大部分情況都能很快捷的處理;
- 沒有空指針的問題;
- 還有很多優點待發掘。
缺點
- ButterKnife好像更方便;
- 復雜的布局處理起來很困難;
- IDE不夠完善。
- 還有很多缺點待發現。
來自:http://www.iamxiarui.com/2016/08/28/android:databinding的一二事/