Adroid Data Binding数据绑定对比(findViewXX、ButterKnife)
9.1 数据绑定基础对比// 传统方式 - findViewByIdclassUserActivity:AppCompatActivity(){privatelateinitvartvName:TextViewprivatelateinitvartvAge:TextViewprivatelateinitvartvEmail:TextViewprivatelateinitvartvPhone:TextViewprivatelateinitvartvAddress:TextViewprivatelateinitvarbtnUpdate:ButtonoverridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)setContentView(R.layout.activity_user)// 大量的 findViewById 调用tvNamefindViewById(R.id.tvName)tvAgefindViewById(R.id.tvAge)tvEmailfindViewById(R.id.tvEmail)tvPhonefindViewById(R.id.tvPhone)tvAddressfindViewById(R.id.tvAddress)btnUpdatefindViewById(R.id.btnUpdate)// 加载用户数据loadUserData()}privatefunloadUserData(){valuseruserRepository.getUser(123)// 手动更新每个 ViewtvName.textuser.name tvAge.textuser.age.toString()tvEmail.textuser.email tvPhone.textuser.phone tvAddress.textuser.address}privatefunupdateUser(user:User){// 手动更新每个 ViewtvName.textuser.name tvAge.textuser.age.toString()tvEmail.textuser.email tvPhone.textuser.phone tvAddress.textuser.address}}// 1. ButterKnife 绑定控件 BindView(R.id.tv_name)// 对应布局 TextView idTextView tvName;BindView(R.id.tv_age)TextView tvAge;// - ButterKnifeBindView(R.id.tv_name)// 对应布局 TextView idTextViewtvName;BindView(R.id.tv_age)TextViewtvAge;OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 1. 初始化 ButterKnifeButterKnife.bind(this);// 3. 直接赋值setDataToView();}传统方式的问题问题说明影响样板代码大量的 findViewById 调用代码冗余难以维护手动更新需要手动更新每个 View容易遗漏容易出错可读性差UI 逻辑与业务逻辑混合代码可读性差类型不安全使用字符串 ID 获取 View运行时错误难以测试UI 逻辑与业务逻辑耦合难以单元测试// 使用 Data BindingclassUserActivity:AppCompatActivity(){privatelateinitvarbinding:ActivityUserBindingprivatelateinitvarviewModel:UserViewModeloverridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)// 设置绑定bindingDataBindingUtil.setContentView(this,R.layout.activity_user)viewModelViewModelProvider(this).get(UserViewModel::class.java)// 设置数据binding.viewModelviewModel binding.lifecycleOwnerthis// 数据更新会自动反映到 UI 在xml布局文件中使用UserviewModel.loadUser(123)}}Data Binding 的优势优势说明消除样板代码自动生成 View 的引用无需 findViewById自动 UI 更新数据变化自动反映到 UI类型安全编译时检查避免运行时错误代码简洁UI 逻辑与业务逻辑分离易于测试UI 逻辑可以独立测试9.2 Data Binding 快速入门9.2.1 启用 Data Binding在 build.gradle 中启用android { // ... dataBinding { enabled true } }9.2.2 创建布局文件布局文件结构?xml version1.0 encodingutf-8?layoutxmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsdata!-- 定义数据变量 --variablenameusertypecom.example.app.model.User/variablenameviewModeltypecom.example.app.viewmodel.UserViewModel/importtypeandroid.view.View//dataandroidx.constraintlayout.widget.ConstraintLayoutandroid:layout_widthmatch_parentandroid:layout_heightmatch_parenttools:context.ui.user.UserActivity!-- 用户名 --TextViewandroid:idid/tvNameandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text{user.name}android:textSize20spandroid:textStyleboldapp:layout_constraintTop_toTopOfparentapp:layout_constraintStart_toStartOfparentapp:layout_constraintEnd_toEndOfparentandroid:layout_marginTop50dp/!-- 年龄 --TextViewandroid:idid/tvAgeandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text{string/age_format(user.age)}android:textSize16spapp:layout_constraintTop_toBottomOfid/tvNameapp:layout_constraintStart_toStartOfparentapp:layout_constraintEnd_toEndOfparentandroid:layout_marginTop20dp/!-- 邮箱 --TextViewandroid:idid/tvEmailandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text{user.email}android:textSize16spapp:layout_constraintTop_toBottomOfid/tvAgeapp:layout_constraintStart_toStartOfparentapp:layout_constraintEnd_toEndOfparentandroid:layout_marginTop20dp/!-- 电话 --TextViewandroid:idid/tvPhoneandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text{user.phone}android:textSize16spapp:layout_constraintTop_toBottomOfid/tvEmailapp:layout_constraintStart_toStartOfparentapp:layout_constraintEnd_toEndOfparentandroid:layout_marginTop20dp/!-- 地址 --TextViewandroid:idid/tvAddressandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text{user.address}android:textSize16spapp:layout_constraintTop_toBottomOfid/tvPhoneapp:layout_constraintStart_toStartOfparentapp:layout_constraintEnd_toEndOfparentandroid:layout_marginTop20dp/!-- 更新按钮 --Buttonandroid:idid/btnUpdateandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text更新android:onClick{() - viewModel.updateUser()}android:visibility{viewModel.isLoading ? View.GONE : View.VISIBLE}app:layout_constraintTop_toBottomOfid/tvAddressapp:layout_constraintStart_toStartOfparentapp:layout_constraintEnd_toEndOfparentandroid:layout_marginTop30dp/!-- 加载进度条 --ProgressBarandroid:idid/progressBarandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:visibility{viewModel.isLoading ? View.VISIBLE : View.GONE}app:layout_constraintTop_toBottomOfid/tvAddressapp:layout_constraintStart_toStartOfparentapp:layout_constraintEnd_toEndOfparentandroid:layout_marginTop30dp//androidx.constraintlayout.widget.ConstraintLayout/layout9.2.3 在 Activity 中使用 Data Binding/** * 用户 Activity */classUserActivity:AppCompatActivity(){privatelateinitvarbinding:ActivityUserBindingprivatelateinitvarviewModel:UserViewModeloverridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)// 使用 DataBindingUtil.setContentView 代替 setContentViewbindingDataBindingUtil.setContentView(this,R.layout.activity_user)viewModelViewModelProvider(this).get(UserViewModel::class.java)// 设置数据到绑定对象binding.viewModelviewModel binding.lifecycleOwnerthis// 加载用户数据valuserIdintent.getStringExtra(USER_ID)?:viewModel.loadUser(userId)}}以上是对比以及快速入门参考案例。