咱們爲何要使用 DataBinding

本文默認讀者有必定的Android開發經驗,對Android Annotations和DataBinding技術也有了簡單的瞭解。php

文章經過三種不一樣方式代碼的對比,最後總結說明爲何要使用DataBinding的技術。前端

功能

三種不一樣方式代碼須要實現的功能是在登陸界面裏,經過監聽用戶名和密碼輸入框的文本變化,動態控制登陸按鈕點擊狀態。java

第一種:普通實現

採用普通方式編寫代碼,能夠發現會有不少的多餘地方,大部分都是重複的工做:android

  • 實例化view:findViewById(...)
  • 添加文本監聽:addTextChangedListener(...)
  • 設置點擊事件:setOnClickListener(...)

xml文件有兩個EditText和一個Button,比較簡單,這裏就不貼代碼了,只貼出Activity代碼:angularjs

public class LoginNormalActivity extends AppCompatActivity {
    private EditText nameEdit;
    private EditText pwdEdit;
    private Button loginBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...

        //實例化view
        nameEdit = (EditText) findViewById(R.id.login_name_edit);
        pwdEdit = (EditText) findViewById(R.id.login_pwd_edit);
        loginBtn = (Button) findViewById(R.id.login_btn);

        //添加文本變化監聽
        OnTextChangeListener textChangeListener = new OnTextChangeListener();
        nameEdit.addTextChangedListener(textChangeListener);
        pwdEdit.addTextChangedListener(textChangeListener);

        //登陸按鈕點擊事件監聽
        loginBtn.setOnClickListener(v -> Toast.makeText(this, "click login!", Toast.LENGTH_SHORT).show());

        updateLoginEnable();
    }

    /** * 更新登陸按鈕的狀態 */
    private void updateLoginEnable() {
        loginBtn.setEnabled(!(TextUtils.isEmpty(nameEdit.getText()) || TextUtils.isEmpty(pwdEdit.getText())));
    }

    /** * 文本變化監聽Listener */
    private class OnTextChangeListener implements TextWatcher {
        ...

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            //在文本變化結束後去更新
            updateLoginEnable();
        }
    }
}複製代碼

第二種:Android Annotations實現

註解方式編寫代碼,讓你專一於真正重要的地方,使代碼更加精簡:ide

  • 經過註解@ViewById @Click @AfterTextChange解決不少重複工做
  • 在編譯期經過APT生成一個新的類,命名規則是原始類名加下劃線,沒有使用反射,不會影響程序運行時的效率,可是新的編譯出來的類會讓增長你的認知,用起來稍有不爽。

xml文件有兩個EditText和一個Button,比較簡單,一樣也就不貼代碼了,只貼出Activity代碼:工具

@EActivity(R.layout.login_activity)
public class LoginAnnotationActivity extends AppCompatActivity {
    //實例化view
    @ViewById(R.id.login_name_edit)
    protected EditText nameEdit;
    @ViewById(R.id.login_pwd_edit)
    protected EditText pwdEdit;
    @ViewById(R.id.login_btn)
    protected Button loginBtn;

    @AfterViews
    protected void initView() {
        updateLoginEnable();
    }

    /** * 更新登陸按鈕的狀態 */
    private void updateLoginEnable() {
        loginBtn.setEnabled(!(TextUtils.isEmpty(nameEdit.getText()) || TextUtils.isEmpty(pwdEdit.getText())));
    }

    /** * 登陸點擊回調 */
    @Click(R.id.login_btn)
    protected void login(View view) {
        Toast.makeText(this, "click login!", Toast.LENGTH_SHORT).show();
    }

    //添加文本變化監聽
    @AfterTextChange({R.id.login_pwd_edit, R.id.login_name_edit})
    protected void afterTextChange(TextView tv, Editable text) {
        //在文本變化結束後去更新
        updateLoginEnable();
    }
}複製代碼

第三種:DataBinding實現

綁定方式:去除了冗餘代碼的基礎上對數據和UI層進行解耦 this

  • 經過android:text="@={...}"將數據雙向綁定到UI中
  • 經過android:enabled="@{...}"控制按鈕狀態
  • 經過android:onClick="@{...}"直接處理用戶操做事件
  • 編譯期同過APT生成輔助工具類,實現數據和UI的動態綁定

首先xml文件代碼:spa

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="loginViewHelper" type="com.free.fastmvpdemo.login.LoginViewHelper" />
    </data>

    <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingLeft="20dp" android:paddingRight="20dp">

        <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:hint="@string/account_hint" android:text="@={loginViewHelper.name}" />

        <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:hint="@string/pwd_hint" android:text="@={loginViewHelper.pwd}" />

        <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:enabled="@{loginViewHelper.canLogin(loginViewHelper.name,loginViewHelper.pwd)}" android:onClick="@{loginViewHelper.login}" android:text="@string/login" />
    </LinearLayout>
</layout>複製代碼

上面xml代碼咱們能夠看出,數據綁定規則已經放在裏面了,其實java代碼的只須要處理業務相關的邏輯就行了,很是的清晰,而後Activity和輔助Helper代碼:雙向綁定

public class LoginActivity extends AppCompatActivity {
    //DataBinding自動生成的類,命名規則是取xml文件名加Binding結尾
    LoginActivityBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...

        //初始化data bind,並設置Helper實例
        binding = DataBindingUtil.setContentView(this, R.layout.login_activity);
        binding.setLoginViewHelper(new LoginViewHelper());

    }
}

 public class LoginViewHelper {
        //監聽屬性
        public ObservableField<String> name = new ObservableField<>();
        public ObservableField<String> pwd = new ObservableField<>();

        /** * 登陸點擊回調 */
        public void login(View view) {
            Toast.makeText(view.getContext(), "click login!", Toast.LENGTH_SHORT).show();
        }

        /** * 是否能夠登陸 */
        public boolean canLogin(String name, String pwd) {
            return !(TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd));
        }
    }複製代碼

總結

  • 普通方式:過多的冗餘代碼,因此咱們應該拋棄普通方式,擁抱新的技術,解放雙手
  • 註解方式:經過註解解決絕大多數的重複工做,而且沒有使用反射,不影響程序的運行效率,只是須要多認知一些類,使用稍有不爽。不過在一些Activity跳轉廣播接收中,經過註解會有自然的優點,可使你的代碼更清晰。
  • 綁定方式:數據驅動:數據變化後自動更新UI;事件處理:直接找到目標實例處理用戶操做的事件。這樣咱們就不須要和UI或者控件打交道,只須要在java代碼中處理業務邏輯就行了,很是清晰,其他的統一交給binding庫去完成。下降了代碼耦合度,使得數據獨立於UI,對之後程序的變化和維護都有積極的影響。長遠考慮下首選綁定方式.

最後吐槽一下:目前Android的綁定和前端的angularjs相比還有不小的差距,尤爲是在雙向綁定這一塊,另外Android studio對DataBinding的報錯和代碼自動生成這方面的支持也不太友好。固然這只是現狀,會慢慢變好的。

相關文章
相關標籤/搜索