秒懂Android开发之DataBinding详解 (part 1)

【版权申明】非商业目的注明出处可自由转载
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/106267286
出自:shusheng007

概述

DataBinding 最早应该是在2015年末的时候就被提出了,那我为什么现在才写一些相关的文章呢?因为我不喜欢也不看好这项技术!那为什么又要写呢?因为目前公司的项目中在用,无论我喜不喜欢都需要使用,我的吃饭啊!

我是不会在自己可以主导的项目中主动使用此技术的,那为什么我这么讨厌它呢?

主要是因为我认为其会给项目维护带来糟糕的体验。DataBinding使的程序员可以在layout文件中写代码了,也就是可以将业务逻辑混合在视图文件中了,这不仅降低了layout文件的重用性,还使View与业务逻辑一定程度绑定了。虽然Google一直在强调,不要再layout文件中使用复杂的表达式,但是你要知道给同一个项目提交代码的不仅有经验丰富的王二狗,也会有实习生牛翠花,还可能有外包林蛋大,code review 在很多公司根本没有或者就是一个摆设。

但是你也不用太担心,虽然我不喜欢它但是不妨碍喜欢它的你学习此项技术。我准备以3篇文章总结一下这个库的一些知识

  1. 使用入门
  2. Binding Adatper,双向绑定等
  3. 与LiveData 等架构组件配合,以及原理等

DataBinding 总览

我们知道,Android的UI一般是使用 xml 格式的layout文件表示的, 要想为UI上的view赋值,首先需要在代码中获取到相应的view,即 findViewById

最开始那一帮写Android的也没觉得有什么不好,大家都这么用,世界一片和谐。但是突然有些不安分的程序员(例如JakeWharton)不干了:这太TM繁琐了,能不能有更好的办法呢, 于是参考其他程序员的想法写出了 ButterKnife 。就这样又过了两年,随着Android生态的壮大与稳定,Google Android 团队终于有时间开始搞事情了,于是Jetpack横空出世。DataBinding也被收归其旗下了,是其中解决View绑定的库,但是感觉一下用力过猛,弄成DataBinding了,最近又出了ViewBinding,也许是一个纠正吧。我认为ViewBinding才是解决这个问题的希望,强烈建议阅读文章 秒懂Android开发之ViewBinding,一代神器ButterKnife的终结者

本文包含如下内容:

  1. DataBinding 简单介绍
  2. DataBinding 试图解决的问题及其使用场景
  3. DataBinding 的入门使用

简介

Data Binding 类库是 Android Jetpack 的一部分,通过它你可以将数据与UI元素的绑定工作(就是互相赋值)在layout 文件中以声明的方式完成,而不是在viewControlor,例如Activity,Fragment 中。

例如我们要给一个Textview赋值,传统方式代码如下:

findViewById<TextView>(R.id.user_namet).apply {
    text = viewModel.userName
}

而使用data binding后就可以将赋值的逻辑放到layout文件中了。

<TextView
	...
    android:text="@{viewmodel.userName}" />

整体来说呢就这么点东西,但是铺开了还是有些看头的,所以小伙伴们搬好小板凳,准备开讲。

解决的问题及其使用场景

解决的问题主要有两点:

  1. 省去程序员自己调用 findViewById获取UI元素,使用程序生成
  2. 数据与UI相互赋值问题,包括事件

data binding的精髓应该在第二点上,如果你仅仅是想去掉烦人的findViewById ,那么Google新推出的 ViewBinding 更加适合,因为其简单而高效。

实战使用

纸上得来终觉浅,绝知此事要躬行。看半天如果自己不动手写一下,那都是一团浆糊,等到用的时候还是不会,让我们一起coding起来

前提:Android Studio 4.0

我们准备开发如下图所示的一个页面,通过下面两个按钮动态修改红框中的文字
在这里插入图片描述

  1. 打开data binding 功能
    在要使用data binding 的Module 的gradle 文件中如下配置即可
android{
	...
	    buildFeatures {
       		 dataBinding = true
    }
}

如果使用Kotlin 请记得使用 kotlin-kapt 插件

apply plugin: 'kotlin-kapt'

注意:如果你的项目引用了一个使用了data binding的类库,那么你就被绑架了,你也必须开启data binding,所以如果你在写一个类库,请慎重使用此技术。

  1. 将你的layout文件改成data binding 要求的格式
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data >
		...
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".databinding.DataBindingActivity">

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

最外层必须是<layout>标签,那个<data>标签里面存放要在layout中引用的数据。那个ConstraintLayout 才是我们需要的UI.

值得说明的是,AndroidStudio支持将普通的layout转换为dataBinding需要的layout格式。

在需要转换的layout文件中外层View右键,选择Context Actions,然后选择转换为data binding layout 即可。如下图所示
在这里插入图片描述

  1. 与ViewControlor绑定

    即让我们的Activity等视图控制器与data binding 生成的类绑定,如下所示

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityDataBindingBinding =
                     DataBindingUtil.setContentView(this, R.layout.activity_data_binding)
    }

这里使用了DataBindingUtil 来进行绑定,除此之外,那个layout文件的生成类ActivityDataBindingBinding里还有几个静态inflate(...)方法可以用于绑定.

  1. 在layout文件中书写表达式

当完成以上3步后就可以在layout文件里面写表达式了。

首先在<data> 标签里面声明声明变量,声明好了就可以在表达式中引用了,例如本例中声明了viewModel作为变量。

    <data >
        <variable
            name="viewModel"
            type="top.ss007.androiddevmemo.databinding.DataBindingViewModel" />
    </data>

第二在view中书写表达式,在表达式中就可以引用我们声明的变量了,例如我的ViewMode文件如下

class DataBindingViewModel : ViewModel() {

    var action: String = "邀请牛翠花晚上一起生猴子"
    var targetGirl: Girl = Girl("牛翠花",30)


    fun seduceGirl(girl: Girl) {
        targetGirl = Girl("上官无雪", 18)
        action = "邀请${girl.age.toString() + "的" + girl.name}晚上一起看月亮"
    }

    fun bornSon(girl: Girl) {
        targetGirl = Girl("牛翠花", 30)
        action = "邀请${girl.age.toString() + "的" + girl.name}晚上一起生猴子"
    }

}

其中Girl 是一个普通的data class

我就可以使用其中的变量和方法了

为TextView 赋值

        <TextView
            android:id="@+id/tv_action"
            ...
            android:text="@{viewModel.action}"/>

为Button设置点击事件

        <Button
            android:id="@+id/btn_born_son"
			...
            android:onClick="@{(view)->viewModel.bornSon(viewModel.targetGirl)}"
            />

那到此是不是就已经好了呢?非常可惜,还差最后一步,因为你想想,你在layout中声明了viewModel变量,但是我们没有为其赋值啊,那他肯定是个null,所以视图中自然也获取不到值。

值得说明的是,其不会崩溃,因为dataBinding做了处理,这点还是比较赞的。

  1. 给layout文件中声明的变量赋值
        override fun onCreate(savedInstanceState: Bundle?) {
        ...
        val viewModel = ViewModelProvider(this).get(DataBindingViewModel::class.java)
        binding.viewModel = viewModel
    }
    

完成以上5步后就大功告成了,感觉自己好牛逼。但是当你满心欢喜的去点击下面的按钮时,UI尽然没有任何反应! 纳尼?what happened? 什么情况?稳住,我们能懂。。。

绑定可观察数据(observable data)

我们在点击按钮时更新了数据,但是发现UI并没有更新,这不是我们想要的啊。那是因为我们的数据是普通的数据,要想当数据改变时通知UI,需要此数据为observable data

可观察数据分为三类

  • Objects

实现了androidx.databinding.Observable 接口的类,google给很贴心的帮我们实现了一个BaseObservable, 我们一般都是继承这个类, 负责在属性值改变时通知data binding一下。

方法为:用@Bindable 标记getter, 同时在setter里调用notifyPropertyChanged方法 即可。

例如本例代码如下

class Girl : BaseObservable() {
    @get:Bindable
    var name: String = ""
        set(value) {
            field = value
            notifyPropertyChanged(BR.name)
        }

    @get:Bindable
    var age: Int = 18
        set(value) {
            field = value
            notifyPropertyChanged(BR.age)
        }
}
  • Fields

dataBinding 类库提供的封装 ObservableField<T>,例如要使一个String变量可以观察可如下定义:

val action: ObservableField<String> = ObservableField("邀请牛翠花晚上一起生猴子")

其还为int, boolean, long 等基础类型提供了相应的实现,相比ObservableField其在进行访问操作时不进行装箱和拆箱,效率有所提高。

ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble
ObservableParcelable

  • Collections
    ObservableArrayMapObservableArrayList

运行结果

当把我们的数据修改为可Observable data后再次运行,点击按钮时,UI也会随之改变。

在这里插入图片描述

总结

至此,相信你已经可以非常自信的上手DataBinding了,你今天又不用加班了,开心哇??

在文中我没有过多的提及layout中表达式的语法,一是因为本文目的是让你快速上手,二是因为我认为这个在你使用遇到困难时查官方文档才是正解。

下一篇让我们一起看一下 Binding Adapter 以及双向绑定。

如果你觉得对你有用,请反手给我一个赞,如果你还想随时找到我,请猛戳关注按钮。

望你保重身体,享受编码,享受生活。

本文源码下载地址:AndroidDevMemo
官方教程:Data Binding Library

猜你喜欢

转载自blog.csdn.net/ShuSheng0007/article/details/106267286