Android Jetpack DataBinding入门填坑(三)

Jetpack系列
Android Jetpack WorkManager初级认识
Android Jetpack ViewModel由浅入深

附上官网地址https://developer.android.com/topic/libraries/data-binding/expressions

一、DataBinding的定义及作用

是一个支持库,使用该库,您可以使用声明性格式而非编程方式将布局中的UI组件绑定到应用程序中的数据源。不需要在使用findViewById之类的,布局文件也不再简单的是一个布局文件,可以包含数据以及逻辑。

配置必要信息

Build.gradle文件添加下面信息

android {
    ...
    dataBinding {
        enabled = true
    }
}

二、基本使用

1. 简单展示绑定过程
  1. 新建activity_databinding.xml


  // 定义数据的标签
    
        
    
 // 定义布局的标签

    




上面的格式:包含两个子标签,

  1. 定义我们的数据的地方,
  2. ,这个布局就相当于我们平时的布局。
    TextViewtext绑定了android:text="@{title}",如果第一次设置title数据变化,页面就会跟着变化。

这里解释一下标签中的属性,
name是定义的变量名
type是变量的类型

  1. 新建Acitivity绑定布局
class DatabasingActivity : AppCompatActivity() , View.OnClickListener {


    lateinit var mactivityBinding: ActivityDatabindingBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //绑定布局
        mactivityBinding = DataBindingUtil.setContentView(this,R.layout.activity_databinding)
        mactivityBinding.title = "基础使用"
    }
}

上面的ActivityDatabindingBinding是系统自动帮我们生成的,使用DataBindingUtil.setContentView(this,R.layout.activity_databinding)便可以绑定好布局,(不需要像以前调用setContentView()),mactivityBinding.title = "基础使用"赋值给title,textView就会自动展示出数据了。

注意点:

  1. ActivityDatabindingBinding是根据你的布局.xml去生成的 这里的是activity_databinding.xml所以生成ActivityDatabindingBinding.
  2. 如果发现databinding生成的ActivityDatabindingBindingImpl(看自己的命名)中出现路径报错,那么最大的可能性是你的.xml文件里面写错了之类的!!!

下面看一下.xml文件支持什么表达式。

三、支持的表达式:

  • 数学计算符 + - / * %
  • 字符连接符号 +
  • 逻辑运行符号 && ||
  • 二元运行符号 & | ^
  • 一元运行符号 + - ! ~
  • 移位 >> >>> <<
  • 比较符号 == > < >= <=(请注意,<必须转义为<)
  • instanceof
  • Grouping ()
  • character, String, numeric, null
  • cast
  • 方法调用
  • 现场访问
  • Array存取 []
  • 三元运算符 ?:

四、 不支持的表达式:

  • this
  • super
  • new
  • explicit generic invocation (显式泛型调用)

五、 设置点击事件跟导入数据类

  1. 新建数据实体类
data class Person(var Name:String,var Age:Int)
  1. 修改一下布局文件


    
      //关键点1
        
       //关键点2
        
     //关键点3
        
        
    


    
//关键点4
    
//关键点4
    

关键代码1: 导入数据类所在的路径包名,要导入后才能使用
关键代码2:定义Person类型的变量
关键代码3:定义android.view.View.OnClickListenerView的点击事件
关键代码4:在Buttonandroid:onClick="@{onClickListener}中引用关键代码3定义的点击事件
3 修改一下Activity文件

class DatabasingActivity : AppCompatActivity() , View.OnClickListener {


    lateinit var mactivityBinding: ActivityDatabindingBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //绑定布局
        mactivityBinding = DataBindingUtil.setContentView(this,R.layout.activity_databinding)
        //赋值给布局中定义的中的面的peronInfo
        mactivityBinding.peronInfo = Person("man",18)
        //实现布局中定义的中的onClickListener变量,这里传入this,记得要实现接口
        mactivityBinding.onClickListener = this
    }
    //当点击按钮的时候就会自动调用到这里了
    override fun onClick(v: View?) {
        when(v){
            mactivityBinding.button7 -> {
                mactivityBinding.textView.text = "这个是点击button7产生的"
            }
            mactivityBinding.button8 ->{
                mactivityBinding.textView2.text = "这个是点击button8产生的"
            }
        }
    }
}

直接看上面注释就知道用法了

上面的注释看懂就可以了,Activity中基本的DataBinding你就算是掌握了,关于点击事件的还有很多种写法,可能需要重新写一篇详细的说一下其它的细节吧。

六、在Fragment中使用

    lateinit var fragmentTestBinding:FragmentTestBindingBinding
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        fragmentTestBinding = DataBindingUtil.inflate(inflater,R.layout.fragment_test_binding,container,false)
        return fragmentTestBinding.root
    }

Activity对比Fragment这里就是DataBindingUtil.inflate()传参不同,然后返回fragmentTestBinding.root。其它的操作都是一样的

七、单向绑定数据(可观察的数据对象)

最开始使用的时候我很不理解为什么还有个单向绑定。因为我看到基本类型的数据,在xmldata定义 然后再Activity中更改,页面会跟着一起刷新,这不就是相当于单向绑定了吗???直到后面我在节点中import入自定义的数据类bean,然后再在Activity中更改bean中的成员变量时,页面并没有改变。这时候我才懂了这个存在的原因。(ps:这个只是个人刚接触的时候想法,新手有可能也有会这样想法,我这里先说一下)

官网定义:任何普通的旧对象都可以用于数据绑定,但是修改对象不会自动导致UI更新。数据绑定可用于使您的数据对象在数据更改时通知其他对象(称为侦听器)。有三种不同类型的可观察类: 对象,字段和集合

实现的基本方法有以下几种

1. 直接定义可监听变量
  • ObservableBoolean
  • ObservableByte
  • ObservableChar
  • ObservableShort
  • ObservableInt
  • ObservableLong
  • ObservableFloat
  • ObservableDouble
  • ObservableParcelable
//定义的实体bean时候
class Person {
    val Name = ObservableField()
    val Age = ObservableInt()
}
//(kotlin 语法 )调用实体bean的时候
user.firstName = "Google"
val age = person.Age 
--------------------------------------------------------
//(java 语法 )调用实体bean的时候
person.firstName.set("Man");
int age = person.Age.get();

使用的时候记得使用get(),set()方法。(ps:kotlin语法看来起来是直接调用的,但实际上里面也是实现了get()set()方法)

//可监听变量数组类型

  • ObservableArrayMap<>()
  • ObservableArrayList<>()

----------定义xml文件-----------------------

        
        

}
------------使用的时候----------------------------

ObservableArrayList().apply {
    add("man")
}

用法跟基本类型一致,但是有两点要注意

  1. 记得在import入对应的数组的包名所在路径
  2. 引用这些集合类型的时候,<要改为\< (ps:Android stuido会提醒你这样子操作的 )
2. ObservableField,这个跟上面那些用法一样,泛型传入指定类型。
3. 继承 BaseObservable()
-------------------------------kotlin写法-----------------------------
class User :BaseObservable(){
    @get:Bindable
    var name:String = ""
    set(value) {
        field = value
        notifyPropertyChanged(BR.name)
    }
    @get:Bindable
    var age:Int = 0
    set(value) {
        field = value
        notifyPropertyChanged(BR.age)
    }
}
--------------------------------java写法---------------------------------
private static class User extends BaseObservable {
    private String firstName;
    private String lastName;

    @Bindable
    public String getFirstName() {
        return this.firstName;
    }

    @Bindable
    public String getLastName() {
        return this.lastName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
        notifyPropertyChanged(BR.firstName);
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
        notifyPropertyChanged(BR.lastName);
    }
}

实体类继承BaseObservable()

  1. 在对应的字段get方法钱前面加上注解@Bindable ,kotlin@get:Bindable
  2. set方法中修改数据后调用notifyPropertyChanged(BR.name)通知更改数据
  3. 如果数据类的基类不能被改变,可观察到的界面可以实现使用PropertyChangeRegistry对象注册和通知监听器。(补充)

这里有个坑!!! BR总是报错 找不到nameage字段,后来百度需要在对应module项目下的build.gradle上面加上插件

apply plugin: 'kotlin-kapt'

八、双向绑定数据

在xml文件中 单向绑定我们是用@{变量名},双向绑定则是@={变量名}
最常见的需求就是我们的页面输入了。输入的数据要在代码中可以让我们接收到。

 

    

editText数据数据的时候android:text="@={title}"双向绑定数据,TextView中绑定的 android:text="@{title,default =标题}"也会跟着一起变化。

九、在include中使用

在include中:
先定义include_text.xml


    
        
        
    

    
    


在布局中引入


    
        
    


    


include标签中app:peronInfo将数据传入,这里的peronInfo是在include布局中我们自己定义的数据。

十、在viewStub中使用

因为viewStub是属于懒加载的布局,如果不调用inflate,就不会加载。属于安卓上面也是页面优化有一个范畴。

先定义一个viewStub布局页面



    
        
        
    

    


在布局中引入


    
        
    


    


以上的操作跟include的用法一致,不同点在于Activity中的绑定
Activity

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //绑定布局
        mactivityBinding = DataBindingUtil.setContentView(this,R.layout.activity_databinding)
        o.add(0,"第一数据")
        mactivityBinding.peronInfo = Person("man",18,o)
        mactivityBinding.viewStub.viewStub!!.inflate()
    }

关键代码mactivityBinding.viewStub.viewStub!!.inflate()这里就是加载viewStub的地方。

十一、在Adapter中的使用

简化统一可以使用的ViewHolder

public class BaseViewHolder extends RecyclerView.ViewHolder {
    public BaseDataBinding mbinding;

    public BaseViewHolder(BaseDataBinding binding) {
        super(binding.getRoot());
        mbinding = binding;
    }
}

你可以使用上面的ViewHolder就可以不用自己总是去写ViewHolder了。

val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)

AdapteronCreateViewHolder中可以使用上面的方法绑定布局

关于AdapterDataBinding使用的网上有很多文章大家可以自行查阅

这篇文章主要是记录一下自己学习的过程,很多细节化跟封装的话以后再出一篇文章另外记录,有问题的也请同学们在评论区留言,希望看的同学们觉得有用的话给个赞~ 谢谢

你可能感兴趣的:(Android Jetpack DataBinding入门填坑(三))