Android DataBinding庫(MVVM設計模式)

什麼是MVVM

說到DataBinding,就有必要先提起MVVM設計模式。
Model–View–ViewModel(MVVM) 是一個軟件架構設計模式,相比MVVM,大家對MVC或MVP可能會更加熟悉。

MVC:(VIew-Model-Controller)

早期將VIew、Model、Controller代碼塊進行劃分,使得程序大部分分離,降低耦合。

1 MVP:(VIew-Model-Presenter)由於MVC中View和Model之間的依賴太強,導致Activity中的代碼過於臃腫。爲了他們可以絕對獨立的存在,慢慢演化出了MVP。在MVP中View並不直接使用Model,它們之間的通信是通過 Presenter (MVC中的Controller)來進行的。

2 MVVM:(Model–View–ViewModel)
MVVM可以算是MVP的升級版,將 Presenter 改名爲 ViewModel。關鍵在於View和Model的雙向綁定,當View有用戶輸入後,ViewModel通知Model更新數據,同理Model數據更新後,ViewModel通知View更新。

Data Binding

  1. 在Google I/O 2015上,伴隨着Android M預覽版發佈的Data Binding兼容函數庫。
    不知道要扯什麼了,還是直接上代碼,來看看Data Binding的魅力吧。
  2. Data Binding對使用的環境還是有一定要求的(這貨有點挑)
    Android Studio版本在1.3以上
    gradle的版本要在1.5.0-alpha1以上
    需要在Android SDK manager中下載Android Support repository
    然後在對應的Module的build.gradle中添加
android {
      ....
      dataBinding {
          enabled =true
      }
    }

創建一個User類

public class User {
  private String firstName;
  private 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;
  }

  public void setLastName(String lastName) {
      this.lastName = lastName;
  }

  public void setFirstName(String firstName) {
      this.firstName = firstName;
  }
}

在activity_main.xml中佈局

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
  <data>
      <import type="com.example.gavin.databindingtest.User"/>
      <variable
          name="user"
          type="User" />
  </data>
  <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical"
      android:gravity="center"
      >
      <TextView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{user.firstName}"
          android:textSize="20sp" />
      <Button
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{user.lastName}"
          android:textSize="25sp" />
  </LinearLayout>
</layout>

這裏跟平時的佈局有點不同,最外層是layout,裏面分別是是data以及我們的佈局。

data:聲明瞭需要用到的user對象,type用於是定路徑。
可以在TextView中的看到android:text="@{user.firstName}", 這是什麼鬼,沒見過這麼寫的!!!
(不急,繼續往下看)

綁定數據

public class MainActivity extends AppCompatActivity {
  private ActivityMainBinding binding;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
      User user = new User("Micheal", "Jack");
      binding.setUser(user);
  }
}

問我ActivityMainBinding哪來的?我怎麼知道…

ActivityMainBinding是根據佈局文件的名字生成的,在後面加了Binding。

工作原理:

原來Data Binding 在程序代碼正在編譯的時候,找到所有它需要的信息。然後通過語法來解析這些表達式,最後生成一個類。
通過反編譯我們可以看到,Data Binding爲我們生成了databinding包,以及ActivityMainBinding類

這裏寫圖片描述

看看我們在onCreate中最後調用的binding.setUser(user),在ActivityMainBinding中可以看到這個方法。

這裏寫圖片描述

我想就是這個 super.requestRebind()對數據進行了綁定,至於裏面怎麼實現的,有待進一步研究。

上面只是用一個簡單的例子,展示了Data Binding的用法,如果想在實際項目中使用,可不是上面這例子可以搞定的。下面就來說說Data Bindig的更多用法。

首先消除下大家對空指針的顧慮

自動生成的 DataBinding 代碼會檢查null,避免出現NullPointerException。
例如在表達式中@{user.phone}如果user == null 那麼會爲user.phone設置默認值null而不會導致程序崩潰(基本類型將賦予默認值如int爲0,引用類型都會賦值null)

自定義DataBinding名

如果不喜歡自動生成的Data Binding名,我們可以自己來定義
<data class="MainBinding">
  ....
</data>
class對應的就是生成的Data Binding名
導包

跟Java中的用法相似,佈局文件中支持import的使用,原來的代碼是這樣

<data>
   <variable name="user" type="com.example.gavin.databindingtest.User" />
</data>
使用import後可以寫成這樣:

  <data>
      <import type="com.example.gavin.databindingtest.User"/>
      <variable
          name="user"
          type="User" />
  </data>

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
遇到相同的類名的時候:


<data>
  <import type="com.example.gavin.databindingtest.User" alias="User"/>
  <import type="com.example.gavin.mc.User" alias="mcUser"/>
  <variable name="user" type="User"/>
  <variable name="mcUser" type="mcUser"/>
</data>


使用alias設置別名,這樣user對應的就是

com.example.gavin.databindingtest.User,mcUser就對應com.example.gavin.mc.User,然後

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


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
當需要用到一些包時,在Java中可以自動導包,不過在佈局文件中就沒有這麼方便了。需要使用import導入這些包,才能使用。如,需要用到View的時候


<data>
  <import type="android.view.View"/>
</data>
...
<TextView
...
android:visibility="@{user.isStudent ? View.VISIBLE : View.GONE}"
/>


注意:只要是在Java中需要導入包的類,這邊都需要導入,如:Map、ArrayList等,不過java.lang包裏的類是可以不用導包的


表達式

在佈局中,不僅可以使用

android:text="@{user.lastName}"
還可以使用表達式如:

三元運算

在User中添加boolean類型的isStudent屬性,用來判斷是否爲學生。

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{user.isStudent? "Student": "Other"}'
android:textSize="30sp"/>

注意:需要用到雙引號的時候,外層的雙引號改成單引號。
還可以這樣用

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="學生"
android:visibility="@{user.isStudent ? View.VISIBLE : View.GONE}"
android:textSize="30sp"/>
這裏用到的View需要在data中聲明

<data>
   <import type="android.view.View"/>
</data>
注意:android:visibility="@{user.isStudent ? View.VISIBLE : View.GONE}",可能會被標記成紅色,不用管它編譯會通過的

??

除了常用的操作法,另外還提供了一個 null 的合併運算符號 ??,這是一個三目運算符的簡便寫法。

contact.lastName ?? contact.name
相當於

contact.lastName != null ? contact.lastName : contact.name

所支持的操作符如下:
數學運算符 + - / * %
字符串拼接 +
邏輯運算 && ||
二進制運算 & | ^
一元運算符 + - ! ~
位運算符 >> >>> <<
比較運算符 == > < >= <=
instanceof
Grouping ()
文字 - character, String, numeric, null
類型轉換 cast
方法調用 methods call
字段使用 field access
數組使用 [] Arrary access
三元運算符 ? :

顯示圖片

除了文字的設置,網絡圖片的顯示也是我們常用的。來看看Data Binding是怎麼實現圖片的加載的。
首先要提到BindingAdapter註解,這裏創建了一個類,裏面有顯示圖片的方法。

public class ImageUtil {
  /**
   * 使用ImageLoader顯示圖片
   * @param imageView
   * @param url
   */
  @BindingAdapter({"bind:image"})
  public static void imageLoader(ImageView imageView, String url) {
      ImageLoader.getInstance().displayImage(url, imageView);
  }
}
(這方法必須是public static的,否則會報錯)
這裏只用了bind聲明瞭一個image自定義屬性,等下在佈局中會用到。
這個類中只有一個靜態方法imageLoader,裏面有兩參數,一個是需要設置圖片的view,另一個是對應的Url,這裏使用了ImageLoader庫加載圖片。
看看吧它的佈局是什麼樣的吧

<?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 >
      <variable
          name="imageUrl"
          type="String"/>
  </data>

  <LinearLayout

      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical"
      android:gravity="center"
      >
      <ImageView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          app:image = "@{imageUrl}"/>
  </LinearLayout>
</layout>
最後在MainActivity中綁定下數據就可以了

binding.setImageUrl(
  "http://115.159.198.162:3000/posts/57355a92d9ca741017a28375/1467250338739.jpg");
哇靠!!!就這樣?我都沒看出來它是怎麼設置這些圖片的。
不管了,先看看效果。(其中的原理以後慢慢嘮,這裏就負責說明怎麼使用,這篇已經夠長了,不想再寫了)

引用:http://www.cnblogs.com/longjunhao/p/5860353.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章