Android技术知识点:如何使用数据绑定来消除findViewById()

1,064 阅读7分钟

 遇到问题

每次在创建或重新创建视图后使用findViewById()函数来获取对它的引用时,Android 系统都会在运行时遍历视图层次结构来查找它。当您的应用只有少数视图时,这不是问题。然而,生产应用程序可能在一个布局中有几十个视图,即使有最好的设计,也会有嵌套的视图。

考虑一个包含滚动视图的线性布局,该滚动视图包含一个文本视图。对于较大或较深的视图层次结构,查找视图可能需要足够的时间,从而明显降低用户的应用程序速度。在变量中缓存视图会有所帮助,但您仍然必须在每个命名空间中为每个视图初始化一个变量。有了很多视图(View)和多个活动(Activity),这些都累加在一起,这样会导致增加重复代码,降低项目可维护性,即所有开发人员的技术痛点。

技术方案

创建一个包含对每个视图的引用的对象。这个对象,称为Binding对象,可以被你的整个应用程序使用。这种技术称为「数据绑定」。为您的应用创建绑定对象后,您可以通过绑定对象访问视图和其他数据,而无需遍历视图层次结构或搜索数据。

​ 数据绑定有以下好处:

  • 与使用findViewById()的代码相比,代码更短、更易于阅读和维护。
  • 数据和视图明显分开。
  • Android系统只需遍历视图层次结构一次就可以获得每个视图,这种情况发生在应用程序启动期间,而不是在用户与应用程序交互的运行时。
  • 您可以获得访问视图的类型安全性。(类型安全意味着编译器在编译时验证类型,如果您尝试将错误的类型分配给变量,则会引发错误。)

在此任务中,您将设置数据绑定,并使用数据绑定将对findViewById()的调用替换为对绑定对象的调用。

操作步骤

第 1 步:启用数据绑定

要使用数据绑定,您需要在 Gradle 文件中启用数据绑定,因为默认情况下未启用。这是因为数据绑定会增加编译时间并可能影响应用程序启动时间。

1.打开build.gradle (Module: 项目名.app)文件,如下图所示:

2.添加一个「buildFeatures」大括号并设置dataBinding为true,代码如下:

android {
  ...
  
  buildFeatures {
    dataBinding true
  }
}

3.出现同步项目的提示时,点击「立刻同步(Sync Now)」,如果没有提示,请依次执行「文件(File)> 使用Gradle文件来同步项目(Sync Project with Gradle Files)」操作,或直接点击工具栏右侧的Gradle图标,如下图所示:

第 2 步:更改布局文件以用于数据绑定 

要使用数据绑定,您需要使用标签来包装XML 布局。这样根类就不再是视图组,而是包含视图组和视图的布局。然后绑定对象可以识别出布局和其中的视图。

1.打开activity_main.xml文件,并切换到「代码(Code)」选项卡,如下图所示:

2.将之前的ConstraintLayout标签替换为标签。

通常的语法结构,代码如下:

<layout>
   <LinearLayout ... >
   ...
   </LinearLayout>
</layout>

示例代码,​如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center">

    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/btnText" />

    </LinearLayout>

</layout>

「小知识」

依次执行「代码(Code) > 重新格式化代码(Reformat Code)」操作,修复代码缩进即可,如下图所示:

第 3 步:在MainActivity类中创建绑定对象 

将绑定对象的引用添加到MainActivity类内,以便您可以使用它来访问视图。

1.打开MainActivity.kt或MainActivity.java文件,代码如下:

Kotlin

import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

}

Java

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

2.在onCreate()方法上为绑定对象创建一个变量。该变量通常称为binding。binding类型,ActivityMainBinding类是由编译器专门为此主活动创建的。该名称来自布局文件的名称,即activity_main+Binding。

流程思路,如下图所示:

「小知识」

小驼峰式命名法(lower camel case):第一个单字以小写字母开始,第二个单字的首字母大写。例如:firstName、lastName。
大驼峰式命名法(upper camel case):每一个单字的首字母都采用大写字母,例如:FirstName、LastName、CamelCase。

示例代码,如下:

// Kotlin
private lateinit var binding: ActivityMainBinding

// Java
ActivityMainBinding binding;

3.点击ActivityMainBinding,并按下「Alt+Enter(Win版)或Option+Enter(Mac版)」组合键,导入这个缺失的类即可。

导入前,提示「导入ActivityMainBinding」,如下图所示:

 Kotlin

Java

导入后,添加相关的import语句,代码如下:

// Kotlin
import com.fm.test.databinding.ActivityMainBinding

// Java
import com.fm.test.databinding.ActivityMainBinding;

4.使用来自DataBindingUtil类的setContentView()函数来与带有MainActivity类的activity_main布局相关联。此setContentView()函数还负责视图的一些数据绑定设置。在onCreate()中,用以下代码行替换之前的setContentView()函数调用。

替换前

//Kotlin
setContentView(R.layout.activity_main)

//Java
setContentView(R.layout.activity_main);

替换后

//Kotlin
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

//Java
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

5.导入DataBindingUtil类,代码如下:

//Kotlin
import androidx.databinding.DataBindingUtil

//Java
import androidx.databinding.DataBindingUtil;

第 4 步:使用绑定对象替换对findViewById()的所有调用

现在可以将对绑定对象中视图的引用替换为对findViewById()的所有调用。创建绑定对象时,编译器从从布局中视图的ID生成绑定对象中视图的名称。例如,按钮的id属性值是user_btn,和绑定对象中的userBtn一样。

在onCreate()中,将findViewById()替换为引用绑定对象中的ID属性值「注意:以小驼峰式命名法(lower camel case)为准」。将findViewById(R.id.btn)替换为binding.btn,并添加要执行的操作代码,代码如下:

Kotlin

import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.fm.test.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.btn.setOnClickListener(this::clickHandlerFunction)
    }

     private fun clickHandlerFunction(view: View) {
       Toast.makeText(this,"我是未来码匠",Toast.LENGTH_LONG).show()
    }

}

Java

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import com.fm.test.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.btn.setOnClickListener(this::clickHandlerFunction);
    }

    public void clickHandlerFunction(View view) {
        Toast.makeText(this,"我是未来码匠", Toast.LENGTH_LONG).show();
    }
}

提示

如果您在进行更改后看到编译器错误,请选择「构建(Build) > 清理项目(Clean Project)」 ,然后选择「构建(Build)> 重构项目(Rebuild Project)」。这样做通常会更新生成的文件。否则,选择「文件(File) > 项目无效时缓存或重新启动(Invalidate Caches/Restart)」进行更彻底的清理。

您之前了解Resources保存对应用程序中所有资源的引用的对象。在引用视图时,您可以Binding以类似的方式考虑对象;但是,该Binding对象要复杂得多。

运行效果

总结

使用数据绑定替换对findViewById()的调用的步骤:

  1. 在build.gradle (Module: 项目名.app)文件的android部分内启用数据绑定:buildFeatures { dataBinding true }
  2. 在XML布局中使用作为根视图。
  3. 定义绑定变量:private lateinit var binding:ActivityMainBinding(Kotlin) 或 ActivityMainBinding binding
  4. 在MainActivity类内创建绑定对象,将setContentView(R.layout.activity_main)替换为binding = DataBindingUtil.setContentView(this, R.layout.activity_main)。
  5. 用对绑定对象中视图ID属性值的引用替换对findViewById()的调用。例如:findViewById
(R.id.btn)=>binding.btn,即在本例中,视图名是XML文件中的视图ID属性值「注意:以小驼峰式命名法(lower camel case)为准」。

实践出真知,钻研出成果。学习Android的过程不管有多难,我们也要时刻保持一颗上进的心,努力钻研,反复分析,寻找突破口。与此同时,攻克难题也需要我们有足够的耐心,厚积薄发,突破极限。

欢迎各位大佬来阅读我创作的Android开发系列文章。希望大家能针对文章内容提出宝贵意见,同时也欢迎大家能指正问题,进一步地与我探讨改进方案。希望本篇文章能得到大家的鼓励和点赞,大家的支持将是我创作的最大动力。

作者声明

本篇经验系本人依照真实经历原创,需要转载到博客、自媒体平台、技术网站等,未经许可,严格遵守本人的知识版权,谢绝转载。如想转载,请联系本人授权。

联系邮箱:3403978592@qq.com

微信号:X9267543839

QQ:3403978592