Jetpack DataBinding数据绑定

自闭症网瘾萝莉.ら 提交于 2020-08-10 02:12:56

Jetpack DataBinding数据绑定

简介
DataBinding是Google提供的将视图和数据绑定的支持库,主要是为了简化代码,去除findViewById() 等样式代码的调用,借助布局文件中的绑定组件,您可以移除 Activity 中的许多界面框架调用,使其维护起来更简单、方便。还可以提高应用性能,并且有助于防止内存泄漏以及避免发生 Null 指针异常。

依赖
在这里插入图片描述
在app的build.gradle文件中添加依赖:

apply plugin: 'kotlin-kapt'
android {
    ......
    
    //开启dataBinding
    dataBinding {
        enabled = true
    }
}
dependencies {
    ......
    
    //databinding版本跟Gradle版本一致
    kapt "com.android.databinding:compiler:$gradle_version"
}

项目的build.gradle配置如下:

buildscript {
    ext.kotlin_version = '1.3.50'
    ext.gradle_version = '3.5.1'
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:$gradle_version"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

Activity/Fragment中使用DataBinding
可通过在根布局上Alt+Enter(Windows下)快捷键生成绑定布局:
在这里插入图片描述
布局文件acitivity_main.xml代码如下:


<?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>
        <import 
            type="com.zzs.jetpack_databinding.User"
            alias="UserInfo"/>
        <variable
            name="user"
            type="UserInfo" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            ......
            android:text="@{user.name}" />

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

注意:布局文件嵌套layout后,会生成一个binding类,类名为布局文件的名称驼峰式+Binding,如:ActivityMainBinding,如果没有找到binding类,Rebuild Project一下项目就可以了

data属性详解:

  • import:引入数据类型

    type: 数据类型
    alias:类型别名,防止不同路径下的相同类名重复

  • variable:变量声明

    name:布局中使用的类名,如: android:text="@{user.name}"
    type: 设置了别名就使用别名,否则就使用类名,如:User,
    不导入数据类型(不使用import)则使用完整地址,
    如: com.zzs.jetpack_databinding.User


常用数据类型引入:

<data>
        <import type="android.util.SparseArray"/>
        <import type="java.util.Map"/>
        <import type="java.util.List"/>
        <import type="com.zzs.jetpack_databinding.User"/>
        <variable name="list" type="List&lt;String>"/>
        <variable name="sparse" type="SparseArray&lt;String>"/>
        <variable name="map" type="Map&lt;String, String>"/>
        <variable name="index" type="int"/>
        <variable name="key" type="String"/>
        <variable name="user" type="User" />
    </data>
    …
    android:text="@{list[index]}"
    …
    android:text="@{sparse[index]}"
    …
    android:text="@{map[key]}"//没有定义key,可以android:text='@{map["name"]}'
                              //           或者android:text="@{map[`name`]}"
    …
    android:text="@{user.name}"

引用资源:

android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"

注意:要使 XML 不含语法错误,您必须转义 < 字符。例如:不要写成 List 形式,而是必须写成 List<String>。

User数据类:

data class User(
    val name:String,
    val age:Int
)

在Activity中代码如下:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //绑定试图
        val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this,R.layout.activity_main)
        //绑定数据类
        binding.user = User("张三",20)//User是我自己创建的数据类
    }
}

在Fragment中代码如下:

class BlankFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val binding = DataBindingUtil.inflate<FragmentBlankBinding>(inflater,R.layout.fragment_blank, container, false)
        return binding.root
    }
    
}

注意:第一次没有找到DataBindingUtil类,重启一下项目就好了

处理页面点击事件:
布局文件代码:

<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.zzs.jetpack_databinding.User" />
        <variable
            name="myHandles"
            type="com.zzs.jetpack_databinding.MainActivity.MyHandlers" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}"
            android:onClick="@{(view)-> myHandles.onClickUser(view,user)}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

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

Activity/Fragment代码:

class MainActivity : AppCompatActivity() {

     override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val binding =
            DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        binding.user = User("张三", 20)
        //不要忘记写这个,不然点击事件无效
        binding.myHandles = MyHandlers()
    }

    inner class MyHandlers{
        fun onClickUser(view: View,user: User){
            //处理点击事件逻辑
            Toast.makeText(this@MainActivity, user.name, Toast.LENGTH_SHORT).show()
        }
    }
}

RecyclerView中使用DataBinding
RecyclerView布局文件代码:

<layout  xmlns:android="http://schemas.android.com/apk/res/android">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_user"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toTopOf="parent"/>
 
</layout>

item列表布局文件代码:

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="userList"
            type="com.zzs.jetpack_databinding.User" />
    </data>

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

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{userList.name}"
            android:padding="10dp" />

    </LinearLayout>
</layout>

初始化:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val binding =
            DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        val users = ArrayList<User>().apply {
            for (i in 0..10) {
                add(User("张三$i", 20))
            }
        }
        binding.rvUser.layoutManager = LinearLayoutManager(this)
        val adapter = UserAdapter(this, users);
        binding.rvUser.adapter = adapter
        //item点击事件
        adapter.setOnItemClickListener(object : UserAdapter.OnItemClickListener {
            override fun onItemClick(view: View, user: User) {
                Toast.makeText(this@MainActivity, user.name, Toast.LENGTH_SHORT).show()
            }

        })
    }
}

UserAdapter适配器:

class UserAdapter(private val context: Context, private val users: List<User>) :
    RecyclerView.Adapter<UserAdapter.ViewHolder>() {
    private lateinit var mOnClickListener: OnItemClickListener

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            DataBindingUtil.inflate(
                LayoutInflater.from(context),
                R.layout.item_list_user,
                parent,
                false
            )
        )
    }

    override fun getItemCount(): Int {
        return users.size
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val binding = holder.dataBinding
        binding.setVariable(BR.userList, users[position])
        holder.itemView.setOnClickListener {
            //创建回调接口处理item点击事件
            mOnClickListener.onItemClick(it, users[position])
            //也可以不使用回调接口(注释上面的代码),直接在Adapter中处理点击逻辑
            //todo
        }
    }

    inner class ViewHolder(var dataBinding: ViewDataBinding) :
        RecyclerView.ViewHolder(dataBinding.root)

    interface OnItemClickListener {
        fun onItemClick(view: View, user: User)
    }

    fun setOnItemClickListener(onClickListener: OnItemClickListener) {
        this.mOnClickListener = onClickListener
    }

}

显示:
在这里插入图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!