這邊算是對(duì)mvvm的學(xué)習(xí)記錄。大部分都來(lái)自網(wǎng)上娩梨!
先說(shuō)下Data Binding的利弊
優(yōu)勢(shì)
DataBinding 出現(xiàn)以前狈定,我們?cè)趯?shí)現(xiàn) UI 界面時(shí)纽什,不可避免的編寫大量的毫無(wú)營(yíng)養(yǎng)的代碼:比如View.findViewById()
躲叼;比如各種更新 View 屬性的 setter:setText()
枫慷,setVisibility()
或听,setEnabled()
或者setOnClickListener()
等等誉裆。
這些“垃圾代碼”數(shù)量越多,越容易滋生 bug粱腻。
使用 DataBinding绍些,我們可以避免書寫這些“垃圾代碼”遇革。
劣勢(shì)
使用 Data Binding 會(huì)增加編譯出的 apk 文件的類數(shù)量和方法數(shù)量萝快。
新建一個(gè)空的工程著角,統(tǒng)計(jì)打開 build.gradle 中 Data Binding 開關(guān)前后的 apk 文件中類數(shù)量和方法數(shù)量吏口,類增加了 120+产徊,方法數(shù)增加了 9k+(開啟混淆后該數(shù)量減少為 3k+)舟铜。
如果工程對(duì)方法數(shù)量很敏感的話谆刨,請(qǐng)慎重使用 Data Binding。
1.基本MVVM使用
環(huán)境搭配
首先要讓Android Studio使用DataBinding庫(kù)才可以實(shí)現(xiàn)mvvm模式
在項(xiàng)目的主app項(xiàng)目Module內(nèi)加入DataBinding引用
apply plugin: 'com.android.application'
android {
......
dataBinding{
enabled = true
}
......
}
還有一個(gè)注意的就是
- Android Studio版本在1.3以上
- gradle的版本要在1.5.0-alpha1以上
基礎(chǔ)使用
在說(shuō)使用之前我們需要將默認(rèn)的xml布局的最外層加入layout嵌套
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<!--這邊設(shè)置data數(shù)據(jù)-->
......
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<!--這是原來(lái)的xml布局-->
........
</LinearLayout>
</layout>
我們創(chuàng)建如下布局
-
對(duì)TextView EditText Button之類的設(shè)置文本
先創(chuàng)建一個(gè)mvvmString類
public class mvvmString {
private String str1;
private String str2;
private String str3;
public mvvmString(String str1, String str2, String str3) {
this.str1 = str1;
this.str2 = str2;
this.str3 = str3;
}
public String getStr1() {
return str1;
}
public void setStr1(String str1) {
this.str1 = str1;
}
public String getStr2() {
return str2;
}
public void setStr2(String str2) {
this.str2 = str2;
}
public String getStr3() {
return str3;
}
public void setStr3(String str3) {
this.str3 = str3;
}
}
之后我們對(duì)xml布局進(jìn)行設(shè)置
首先是data
<data>
<variable name="string" type="com.gjn.msdemo.mvvm.mvvmString" />
</data>
或者
<data>
<import type="com.gjn.msdemo.mvvm.mvvmString" />
<variable name="string" type="mvvmString" />
</data>
在data內(nèi)加入variable屬性設(shè)置名字和類型
之后我們就可以使用了她我,下面我們對(duì)TextView EditText Button分別設(shè)置
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{string.str1}" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="@{string.str2}"
android:ems="10"
android:inputType="textPersonName" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{string.str3}" />
之后我們對(duì)TestActivity進(jìn)行綁定數(shù)據(jù)和設(shè)置數(shù)據(jù)
public class TestActivity extends AppCompatActivity{
private ActivityTestBinding binding;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_test);
binding.setString(new mvvmString("111","222","按鈕"));
}
}
這邊提下根吁,在哪個(gè)xml下面綁定就會(huì)生成相應(yīng)的Binding
好比這個(gè) R.layout.activity_test 他的生成是按照_進(jìn)行拼接形成ActivityTestBinding這個(gè)類
-
對(duì)ImageView設(shè)置圖片
還是創(chuàng)建一個(gè)mvvmImage類
public class mvvmImage {
@BindingAdapter({"image"})
public static void imageLoader(ImageView imageView, String url){
Glide.with(imageView.getContext()).load(url).into(imageView);
}
}
這邊用了Glide來(lái)加載圖片
之后我們?cè)赿ata中加入新的類型
<data>
<import type="com.gjn.msdemo.mvvm.mvvmString" />
<variable name="string" type="mvvmString" />
<variable name="image" type="String" />
</data>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:image="@{image}" />
中間省略了 LinearLayout等布局
使用只需要在binding中加入設(shè)置的圖片即可
String url = "http://7xi8d6.com1.z0.glb.clouddn.com/20180109085038_4A7atU_rakukoo_9_1_2018_8_50_25_276.jpeg";
binding.setImage(url);
-
對(duì)Button設(shè)置點(diǎn)擊事件
還是先創(chuàng)建一個(gè)mvvmClick類
public class mvvmClick {
public void onClick(View view){
Toast.makeText(view.getContext(), "點(diǎn)擊", Toast.LENGTH_SHORT).show();
}
}
之后設(shè)置data
<data>
<import type="com.gjn.msdemo.mvvm.mvvmString" />
<variable name="string" type="mvvmString" />
<variable name="image" type="String" />
<variable name="click" type="com.gjn.msdemo.mvvm.mvvmClick" />
</data>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{click.onClick}"
android:text="@{string.str3}" />
中間省略了 LinearLayout等布局
在Activity中的使用如下
binding.setClick(new mvvmClick());
點(diǎn)擊了按鈕就會(huì)彈出Toast
這樣就算是綁定了基本的數(shù)據(jù)了
下面貼下完整的Activity和xml布局的代碼
public class TestActivity extends AppCompatActivity{
private ActivityTestBinding binding;
private String url = "http://7xi8d6.com1.z0.glb.clouddn.com/" +
"20180109085038_4A7atU_rakukoo_9_1_2018_8_50_25_276.jpeg";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_test);
binding.setString(new mvvmString("111","222","按鈕"));
binding.setImage(url);
binding.setClick(new mvvmClick());
}
}
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="com.gjn.msdemo.mvvm.mvvmString" />
<variable name="string" type="mvvmString" />
<variable name="image" type="String" />
<variable name="click" type="com.gjn.msdemo.mvvm.mvvmClick" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:image="@{image}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{string.str1}" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="@{string.str2}"
android:ems="10"
android:inputType="textPersonName" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{click.onClick}"
android:text="@{string.str3}" />
</LinearLayout>
</layout>
2.MVVM進(jìn)階使用
-
BaseObservable的使用
讓mvvmStrig繼承BaseObservable并改寫
public class mvvmString extends BaseObservable{
private String str1;
private String str2;
private String str3;
public mvvmString(String str1, String str2, String str3) {
this.str1 = str1;
this.str2 = str2;
this.str3 = str3;
}
@Bindable
public String getStr1() {
return str1;
}
public void setStr1(String str1) {
this.str1 = str1;
notifyPropertyChanged(com.gjn.msdemo.BR.str1);
}
@Bindable
public String getStr2() {
return str2;
}
public void setStr2(String str2) {
this.str2 = str2;
notifyPropertyChanged(com.gjn.msdemo.BR.str2);
}
@Bindable
public String getStr3() {
return str3;
}
public void setStr3(String str3) {
this.str3 = str3;
notifyPropertyChanged(com.gjn.msdemo.BR.str3);
}
}
即對(duì)get數(shù)據(jù)進(jìn)行Bindabel刃宵,設(shè)置屬性之后調(diào)用刷新方法notifyPropertyChanged
這時(shí)候修改數(shù)據(jù)就只要
mvvmString string = new mvvmString("111","222","按鈕");
binding.setString(string);
string.setStr1("333");
string.setStr2("444");
string.setStr3("按鈕2");
就可以修改了牲证。否則如果沒有繼承BaseObservable的話,修改數(shù)據(jù)是需要
如下操作
mvvmString string = new mvvmString("111","222","按鈕");
binding.setString(string);
string.setStr1("333");
string.setStr2("444");
string.setStr3("按鈕2");
binding.setString(string);
就是重新再綁定一次十厢,BaseObservable只是加入了刷新
但是BaseObservable這個(gè)方法還是太麻煩了蛮放,如果類多了包颁。每個(gè)類都寫一個(gè)M綁定...實(shí)在是累人
-
ObservableField的使用
創(chuàng)建新的mvvmString2
public class mvvmString2 {
public final ObservableField<String> str1 = new ObservableField<>();
public final ObservableField<String> str2 = new ObservableField<>();
public final ObservableField<String> str3 = new ObservableField<>();
}
修改 data使用
<data>
<import type="com.gjn.msdemo.mvvm.mvvmString2" />
<variable name="string" type="mvvmString2" />
<variable name="image" type="String" />
<variable name="click" type="com.gjn.msdemo.mvvm.mvvmClick" />
</data>
使用如下
mvvmString2 string2 = new mvvmString2();
binding.setString(string2);
string2.str1.set("text");
string2.str2.set("edit");
string2.str3.set("button");
這樣對(duì)創(chuàng)建M也方便娩嚼,并且設(shè)置也很快捷
-
BindingAdapter的使用
上面在修改圖片的時(shí)候用到了BindingAdapter,這邊就在來(lái)具體說(shuō)下BindingAdapter的使用
首先我們先新建一個(gè)xml布局
act_test_adapter.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>
<variable name="adapter" type="com.gjn.msdemo.mvvm.mvvmAdapter" />
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{adapter.add}"
android:text="add" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:texts="@{adapter.texts}" />
</LinearLayout>
</layout>
我們還創(chuàng)建了一個(gè)新的mvvmAdapter類
public class mvvmAdapter {
public ObservableArrayList<String> texts = new ObservableArrayList<>();
public mvvmAdapter(){
for (int i = 0; i < 5; i++) {
texts.add("text => " + i);
}
}
@BindingAdapter({"texts"})
public static void addTextView(LinearLayout linearLayout, ArrayList<String> texts){
linearLayout.removeAllViews();
for (String text : texts) {
TextView textView = new TextView(linearLayout.getContext());
textView.setText(text);
linearLayout.addView(textView);
}
}
public void add(View v){
texts.add("new text");
}
}
之后修改TestActivity
public class TestActivity extends AppCompatActivity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActTestAdapterBinding binding = DataBindingUtil.setContentView(this,R.layout.act_test_adapter);
binding.setAdapter(new mvvmAdapter());
}
}
實(shí)現(xiàn)效果如下
還有一些使用說(shuō)明
-
自定義Binding名
首先我們創(chuàng)建的Bingding都是按照xml生成的和屎,如果我們不希望這樣生成可以修改data柴信,在里面加入class屬性
例如
<data class="NewBinding">
<variable name="adapter" type="com.gjn.msdemo.mvvm.mvvmAdapter" />
</data>
-
別名
可以再使用導(dǎo)包的時(shí)候設(shè)置別名随常,這樣有利于區(qū)分一些差不多命名的包萄涯,就是在import 加入屬性alias
<data class="NewBinding">
<import type="com.gjn.msdemo.mvvm.mvvmAdapter" alias="testadapter" />
<variable name="adapter" type="testadapter" />
</data>
-
在屬性設(shè)置的時(shí)候要加入包
如果想設(shè)置一些屬性
例如我想設(shè)置view的顯示屬性
稍微對(duì)上面的mvvmAdapter進(jìn)行修改。這邊就貼修改的代碼
mvvmAdapter
public class mvvmAdapter {
public final ObservableField<Boolean> isView = new ObservableField<>();
}
xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data class="NewBinding">
<import type="com.gjn.msdemo.mvvm.mvvmAdapter" alias="testadapter" />
<import type="android.view.View" />
<variable name="adapter" type="testadapter" />
</data>
<!-- 其他布局-->
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{adapter.add}"
android:visibility="@{adapter.isView ? View.VISIBLE : View.GONE}"
android:text="add" />
<!-- 其他布局-->
</layout>
activity
public class TestActivity extends AppCompatActivity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ActTestAdapterBinding binding = DataBindingUtil.setContentView(this,R.layout.act_test_adapter);
NewBinding binding = DataBindingUtil.setContentView(this,R.layout.act_test_adapter);
mvvmAdapter adapter = new mvvmAdapter();
binding.setAdapter(adapter);
adapter.isView.set(false);
}
}
資料
【Android】DataBinding庫(kù)(MVVM設(shè)計(jì)模式)
安卓 Data Binding 使用方法總結(jié)(姐姐篇)