咱们为何要使用 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的报错和代码自动生成这方面的支持也不太友好。固然这只是现状,会慢慢变好的。

相关文章
相关标签/搜索