Jetpack之dataBinding

一、概览

数据绑定库(dataBinding)是一种支持库,借助该库,您可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源。

二、使用入门

要将应用配置为使用数据绑定,请在应用模块的 build.gradle 文件中添加 dataBinding 元素

 dataBinding {
        enabled = true
    }

三、布局和绑定表达式

数据绑定布局文件略有不同,以根标记 layout开头,后跟 data 元素和 view 根元素。此视图元素是非绑定布局文件中的根。
User

data class User(val firstName: String, val lastName: String) {
    var like: Int = 0
}

activity_normal

<?xml version="1.0" encoding="utf-8"?>
<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>
      <variable
          name="user"
          type="com.anniljing.jetpackviewmodel.model.User" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".activity.NormalActivity">
      <TextView
          android:id="@+id/normalName"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          app:layout_constraintLeft_toLeftOf="parent"
          app:layout_constraintTop_toTopOf="parent"
          app:layout_constraintRight_toRightOf="parent"
          app:layout_constraintBottom_toBottomOf="parent"/>
        <TextView
            android:id="@+id/normalLike"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintLeft_toRightOf="@id/normalName"
            app:layout_constraintTop_toTopOf="@id/normalName"
            android:text="@{Integer.toString(user.like)}"
            android:layout_marginLeft="20dp"/>
        <Button
            android:id="@+id/addLikeBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintLeft_toLeftOf="@id/normalName"
            app:layout_constraintTop_toBottomOf="@id/normalName"
            android:text="Like"
            android:onClick="addLike"/>
        <TextView
            android:id="@+id/currentLike"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintLeft_toLeftOf="@id/addLikeBtn"
            app:layout_constraintTop_toBottomOf="@id/addLikeBtn"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

data标签

data标签下面有两种子级标签:importvariable,variable 标签为变量,类似于我们定义了一个变量,name 为变量名,type 为变量全限定类型名,包括包名。布局中通过 @{} 来引用这个变量的值,{} 中可以是任意 Java 表达式;

 <variable
          name="user"
          type="com.anniljing.jetpackviewmodel.model.User" />

同样,我们还可以使用import来定义变量

      <import
            alias="User"
            type="com.anniljing.jetpackviewmodel.model.User" />

        <variable
            name="user"
            type="User" />

NormalActivity

class NormalActivity : AppCompatActivity() {
    private var binding:ActivityNormalBinding ?=null
    private val user=User("张三","李四")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding=DataBindingUtil.setContentView(this,R.layout.activity_normal)
        user.like=1
        binding!!.user=user
    }

    fun addLike(view: View) {
         user.like=user.like+1
         binding!!.currentLike.text="当前点赞量:"+user.like
    }
}

在这里插入图片描述
上面截图可以看出,无论怎么增加点赞数,都不会及时的“更新”到UI上,有没有方案实现动态更新UI呢?答案是肯定的,使用可观察的数据对象。

使用可观察的数据对象

可观察性是指一个对象将其数据变化告知其他对象的能力。通过数据绑定库,您可以让对象、字段或集合变为可观察。当其中一个可观察数据对象绑定到界面并且该数据对象的属性发生更改时,界面会自动更新。

可观察字段

在创建实现 Observable 接口的类时要完成一些操作,但如果您的类只有少数几个属性,这样操作的意义不大。在这种情况下,您可以使用通用 Observable 类和以下特定于基元的类,将字段设为可观察字段:

  • ObservableBoolean
  • ObservableBoolean
  • ObservableByte
  • ObservableChar
  • ObservableShort
  • ObservableInt
  • ObservableLong
  • ObservableFloat
  • ObservableDouble
  • ObservableParcelable

ObservableUser

package com.anniljing.jetpackviewmodel.model

import androidx.databinding.ObservableInt

data class ObservableUser(val firstName:String, val like:ObservableInt)

activity_observable_normal

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

    <data>

        <variable
            name="user"
            type="com.anniljing.jetpackviewmodel.model.ObservableUser" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <TextView
            android:id="@+id/normalLike"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:text="@{Integer.toString(user.like)}"/>

        <Button
            android:id="@+id/addLikeBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="addLike"
            android:text="Like" />

        <TextView
            android:id="@+id/currentLike"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>
</layout>

ObservableNormalActivity

package com.anniljing.jetpackviewmodel.activity

import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableInt
import com.anniljing.jetpackviewmodel.R
import com.anniljing.jetpackviewmodel.databinding.ActivityObservableNormalBinding
import com.anniljing.jetpackviewmodel.model.ObservableUser

class ObservableNormalActivity : AppCompatActivity() {
    private lateinit var binding: ActivityObservableNormalBinding
    private val observableUser = ObservableUser("张三", ObservableInt(0))
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding =
            DataBindingUtil.setContentView(this, R.layout.activity_observable_normal)
        binding.user = observableUser
    }

    fun addLike(view: View) {
        observableUser.like.set(observableUser.like.get() + 1)
        binding!!.currentLike.text = "当前点赞量:" + observableUser.like.get()
    }
}

在这里插入图片描述

可观察对象

实现 Observable 接口的类允许注册监听器,以便它们接收有关可观察对象的属性更改的通知。Observable 接口具有添加和移除监听器的机制,但何时发送通知必须由您决定。为便于开发,数据绑定库提供了用于实现监听器注册机制的 BaseObservable 类。实现 BaseObservable 的数据类负责在属性更改时发出通知。具体操作过程是向 getter 分配 Bindable 注释,然后在 setter 中调用 notifyPropertyChanged() 方法

CustomObservableUser

package com.anniljing.jetpackviewmodel.model

import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
import androidx.databinding.library.baseAdapters.BR


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

    @get:Bindable
    var like: Int = 0
        set(value) {
            field = value
            notifyPropertyChanged(BR.like)
        }
}

PS:
1、要导入androidx.databinding.library.baseAdapters.BR
2、如果在notifyPropertyChanged的参数中无法BR指向某个属性时,可以执行android studio工具栏build---->make progect

activity_observable_custom

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

    <data>

        <variable
            name="user"
            type="com.anniljing.jetpackviewmodel.model.CustomObservableUser" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:gravity="center">
        <TextView
            android:id="@+id/normalLike"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:text="@{Integer.toString(user.like)}"/>

        <Button
            android:id="@+id/addLikeBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="addLike"
            android:text="Like" />

        <TextView
            android:id="@+id/currentLike"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>
</layout>

ObservableCustomActivity

package com.anniljing.jetpackviewmodel.activity

import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableInt
import com.anniljing.jetpackviewmodel.R
import com.anniljing.jetpackviewmodel.databinding.ActivityObservableCustomBinding
import com.anniljing.jetpackviewmodel.databinding.ActivityObservableNormalBinding
import com.anniljing.jetpackviewmodel.model.CustomObservableUser
import com.anniljing.jetpackviewmodel.model.ObservableUser

class ObservableCustomActivity : AppCompatActivity() {
    private lateinit var binding: ActivityObservableCustomBinding
    private val observableUser = CustomObservableUser()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding =
            DataBindingUtil.setContentView(this, R.layout.activity_observable_custom)
        binding.user = observableUser
    }

    fun addLike(view: View) {
        observableUser.like=observableUser.like+ 1
        binding!!.currentLike.text = "当前点赞量:" + observableUser.like
    }
}

在这里插入图片描述

四、绑定适配器

绑定适配器负责发出相应的框架调用来设置值。例如,设置属性值就像调用 setText() 方法一样。再比如,设置事件监听器就像调用 setOnClickListener() 方法。
数据绑定库允许您通过使用适配器指定为设置值而调用的方法、提供您自己的绑定逻辑,以及指定返回对象的类型。

指定自定义方法名称

一些属性具有名称不符的 setter 方法。在这些情况下,某个特性可能会使用 BindingMethods 注释与 setter 相关联。注释与类一起使用,可以包含多个 BindingMethod 注释,每个注释对应一个重命名的方法。绑定方法是可添加到应用中任何类的注释。在以下示例中,android:tint 属性与 setImageTintList(ColorStateList) 方法相关联,而不与 setTint() 方法相关联

 /**
     * Applies a tint to the image drawable. Does not modify the current tint
     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
     * <p>
     * Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
     * mutate the drawable and apply the specified tint and tint mode using
     * {@link Drawable#setTintList(ColorStateList)}.
     * <p>
     * <em>Note:</em> The default tint mode used by this setter is NOT
     * consistent with the default tint mode used by the
     * {@link android.R.styleable#ImageView_tint android:tint}
     * attribute. If the {@code android:tint} attribute is specified, the
     * default tint mode will be set to {@link PorterDuff.Mode#SRC_ATOP} to
     * ensure consistency with earlier versions of the platform.
     *
     * @param tint the tint to apply, may be {@code null} to clear tint
     *
     * @attr ref android.R.styleable#ImageView_tint
     * @see #getImageTintList()
     * @see Drawable#setTintList(ColorStateList)
     */
    @android.view.RemotableViewMethod
    public void setImageTintList(@Nullable ColorStateList tint) {
        mDrawableTintList = tint;
        mHasDrawableTint = true;

        applyImageTint();
    }

BindingTintMethods

package com.anniljing.jetpackviewmodel.util

import android.widget.ImageView
import androidx.databinding.BindingMethod
import androidx.databinding.BindingMethods

@BindingMethods(value = [
    BindingMethod(
        type = ImageView::class,
        attribute = "tint",
        method = "setImageTintList")])
class BindingTintMethods {
}

activity_observable_binding_methods

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

    <data>
        <variable
            name="user"
            type="com.anniljing.jetpackviewmodel.model.ObservableUser" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:gravity="center">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{Integer.toString(user.like)}"/>
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_whatshot_black_96dp"
            app:tint="@{user.like > 9 ? @color/star : @android:color/black}" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Like"
            android:onClick="addLike"/>
    </LinearLayout>
</layout>

ObservableBindingMethodsActivity

package com.anniljing.jetpackviewmodel.activity

import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableInt
import com.anniljing.jetpackviewmodel.R
import com.anniljing.jetpackviewmodel.databinding.ActivityObservableBindingMethodsBinding
import com.anniljing.jetpackviewmodel.model.ObservableUser

class ObservableBindingMethodsActivity : AppCompatActivity() {
    private val user: ObservableUser by lazy {
        ObservableUser("张三", ObservableInt(2))
    }

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

    fun addLike(view: View) {
        user.like.set(user.like.get() + 1)
    }

}

在这里插入图片描述在这里插入图片描述

提供自定义逻辑

一些属性需要自定义绑定逻辑,Android 框架类的特性已经创建了 BindingAdapter 注释。如果我们想把上面例子的tint属性和src属性通过一个自定义属性来实现:
ObservableBindingAdapterUser

package com.anniljing.jetpackviewmodel.model

import androidx.databinding.ObservableInt

class ObservableBindingAdapterUser {
    var like: ObservableInt = ObservableInt(0)
        set(value) {
            field = value
        }
    var popularity: ObservableInt by ::like
}

BindingMergeAdapters

package com.anniljing.jetpackviewmodel.util

import android.content.Context
import android.content.res.ColorStateList
import android.widget.ImageView
import androidx.core.content.ContextCompat
import androidx.core.widget.ImageViewCompat
import androidx.databinding.BindingAdapter
import androidx.databinding.ObservableInt
import com.anniljing.jetpackviewmodel.R

object BindingMergeAdapters {
    @BindingAdapter("mergeTintAndSrc")
    @JvmStatic fun mergeTintAndSrc(imageView: ImageView, mergeType: ObservableInt){
        val context:Context=imageView.context
        imageView.setImageResource(R.drawable.ic_whatshot_black_96dp)
        if (mergeType.get()>4){
            ImageViewCompat.setImageTintList(imageView, ColorStateList.valueOf(ContextCompat.getColor(context, R.color.popular)))
        }else if (mergeType.get()>9){
            ImageViewCompat.setImageTintList(imageView, ColorStateList.valueOf(ContextCompat.getColor(context, R.color.star)))
        }
    }
}

activity_observable_binding_adapter

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

    <data>

        <variable
            name="user"
            type="com.anniljing.jetpackviewmodel.model.ObservableBindingAdapterUser" />
    </data>

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

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{Integer.toString(user.like)}" />

        <ImageView
            app:mergeTintAndSrc="@{user.popularity}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="addLike"
            android:text="Like" />
    </LinearLayout>
</layout>

ObservableBindingAdapterActivity

package com.anniljing.jetpackviewmodel.activity

import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.anniljing.jetpackviewmodel.R
import com.anniljing.jetpackviewmodel.databinding.ActivityObservableBindingAdapterBinding
import com.anniljing.jetpackviewmodel.model.ObservableBindingAdapterUser

class ObservableBindingAdapterActivity : AppCompatActivity() {
    private val observableUser: ObservableBindingAdapterUser by lazy {
        ObservableBindingAdapterUser()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityObservableBindingAdapterBinding =
            DataBindingUtil.setContentView(this, R.layout.activity_observable_binding_adapter)
        binding.user = observableUser
    }

    fun addLike(view: View) {
        observableUser.like.set(observableUser.like.get() + 1)
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值