一手遮天 Android - jetpack: DataBinding(MVVM)

项目地址 https://github.com/webabcd/AndroidDemo
作者 webabcd

一手遮天 Android - jetpack: DataBinding(MVVM)

示例如下:

/jetpack/lifecycle/DataBindingDemo.kt

/**
 * DataBinding 就是 android 官方的 MVVM 模式开发框架
 *
 * 如需启用 DataBinding 请在 build.gradle 的 android {} 中做如下配置
 * dataBinding {
 *   enabled = true;
 * }
 * 如需使用 DataBinding 相关注解,则需要在 gradle 中配置 apply plugin: 'kotlin-kapt'
 * 注:DataBinding 需要 gradle 根据你的配置生成一些类,如果遇到问题就 Rebuild Project 重新生成一下
 */

package com.webabcd.androiddemo.jetpack.lifecycle

import android.os.Bundle
import android.util.Log
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.*
import androidx.databinding.Observable
import androidx.databinding.library.baseAdapters.BR
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.webabcd.androiddemo.MyApplication
import com.webabcd.androiddemo.databinding.ActivityJetpackLifecycleDatabindingdemoBinding
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.*

class DataBindingDemo : AppCompatActivity() {

    // ActivityJetpackLifecycleDatabindingdemoBinding 是 gradle 生成的类,其对应的 xml 是 activity_jetpack_lifecycle_databindingdemo.xml
    private lateinit var mBinding: ActivityJetpackLifecycleDatabindingdemoBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 设置 activity 的布局,并获取绑定对象(方式一)
        // binding = DataBindingUtil.setContentView(this, R.layout.activity_jetpack_lifecycle_databindingdemo)

        // 设置 activity 的布局,并获取绑定对象(方式二)
        mBinding = ActivityJetpackLifecycleDatabindingdemoBinding.inflate(layoutInflater)
        setContentView(mBinding.root)

        val myModel = MyDataBindingModel()
        // 指定绑定对象的 lifecycleOwner(用于实现 lifecycleOwner 不在前台则不更新数据)
        mBinding.lifecycleOwner = this
        // 在 xml 的 data 中声明的变量这里都可以使用
        mBinding.buttonText = "我是一个按钮" // 这是一次绑定的方式,这种方式不支持单向绑定或双向绑定
        mBinding.myModel = myModel
        // 在 xml 中的控件,这里也可以通过其 id 使用
        mBinding.button1.setOnClickListener {}

        // 数据发生变化时的通知
        myModel.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
            override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
                if (propertyId == BR.name) {
                    Log.d("lifecycle", "BR.name, ${myModel.name}")
                }
            }
        })

        lifecycleScope.launch {
            repeat(1000) {
                delay(1000)
                val dateFormat = SimpleDateFormat("HH:mm:ss.SSS", Locale.ENGLISH)
                val time = dateFormat.format(Date())

                // 本例用于演示单向绑定
                myModel.name = "${time}"
            }
        }

        // 数据发生变化时的通知
        // 本例用于演示双向绑定,即除了数据层变化会通知 UI 更新数据外,UI 中的数据发生了变化也会通知数据层
        myModel.country.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
            override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
                Log.d("lifecycle", "country: ${myModel.country.get()}")
            }
        })
    }

    override fun onDestroy() {
        super.onDestroy()

        mBinding.unbind()
    }
}

// 自定义类如果想实现单向绑定或双向绑定,需要继承 BaseObservable 类
class MyDataBindingModel : BaseObservable() {

    // 这个 @get:Bindable 注解是必不可少的(如需使用 DataBinding 相关注解,则需要在 gradle 中配置 apply plugin: 'kotlin-kapt')
    @get:Bindable
    var name: String = "123456789"
        set(value){
            field = value
            // BR 是由 gradle 生成的,这里能用 BR.name 是因为 name 属性添加了 @get:Bindable 注解
            // notifyPropertyChanged() - 更新 UI 上的此对象指定字段
            // notifyChange() - 更新 UI 上的此对象的所有字段
            notifyPropertyChanged(BR.name)
        }

    // 通过如下几个类可以实现指定类型数据的单向绑定或双向绑定(下面这几个类都继承自 BaseObservable 类)
    // ObservableBoolean, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble 等
    // ObservableField<T>
    // ObservableList, ObservableMap
    var country: ObservableField<String> = ObservableField<String>()

    // 本例用于演示事件绑定并传参
    fun showName(name: String) {
        Toast.makeText(MyApplication.getInstance().applicationContext, name, Toast.LENGTH_SHORT).show()
    }

    companion object {
        // 本例用于演示静态方法的绑定
        @JvmStatic
        fun substr8(name: String): String {
            return name.substring(0, 8)
        }

        // 本例用于演示 @BindingAdapter 注解的用法
        // 此方法将接管布局文件中的 app:imageUrl 绑定的数据(注:通过 @{} 绑定的数据才会被接管)
        @JvmStatic
        @BindingAdapter(value = ["imageUrl"]) // 如需使用 DataBinding 相关注解,则需要在 gradle 中配置 apply plugin: 'kotlin-kapt'
        fun loadImage(imageView: ImageView, loadUrl:String) {
            Glide.with(imageView).load(loadUrl).into(imageView)
        }
    }
}

/layout/activity_jetpack_lifecycle_databindingdemo.xml

<?xml version="1.0" encoding="utf-8"?>

<!--如需使用 DataBinding,则布局的根节点必须是 layout-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!--
        本布局文件的文件名为 activity_jetpack_lifecycle_databindingdemo.xml
        gradle 会为其生成一个名为 com.webabcd.androiddemo.databinding.ActivityJetpackLifecycleDatabindingdemoBinding 的类
    -->
    <data>

        <!--
            在 data 中也可以指定生成的类的类名
            下面这句 gradle 会为其生成一个名为 com.webabcd.androiddemo.databinding.MyBinding 的类
        -->
        <!--data class="MyBinding"-->

        <!--
            在 data 中也可以指定生成的类的类全名
            下面这句 gradle 会为其生成一个名为 com.webabcd.CustomBinding 的类
        -->
        <!--data class="com.webabcd.CustomBinding"-->

        <!--声明一个指定名称的变量,并指定其类全名-->
        <variable name="myModel" type="com.webabcd.androiddemo.jetpack.lifecycle.MyDataBindingModel" />

        <!--先通过类全名导入一个类,然后再声明一个指定名称的变量,并指定其类名-->
        <import type="com.webabcd.androiddemo.jetpack.lifecycle.MyDataBindingModel" />
        <variable name="myModel2" type="MyDataBindingModel" />

        <!--先通过类全名导入一个类并指定其别名,然后再声明一个指定名称的变量,并指定其类别名-->
        <import type="com.webabcd.androiddemo.jetpack.lifecycle.MyDataBindingModel" alias="MyAlias" />
        <variable name="myModel3" type="MyAlias" />

        <!--声明基本类型的变量-->
        <variable name="buttonText" type="String" />
    </data>

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

        <!--
            @{} - 单项绑定
            @={} - 双向绑定
            @{()->...} - 事件绑定并传参
        -->
        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAllCaps="false"
            android:text="@{buttonText}"
            android:onClick="@{()->myModel.showName(myModel.name)}"/>
        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{myModel.name}"/>
        <EditText
            android:id="@+id/editText1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={myModel.country}"/>

        <!--绑定静态方法-->
        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{MyDataBindingModel.substr8(myModel.name)}"/>

        <!--绑定支持简单表达式-->
        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="输入框中的字符长度小于 1 个我就显示,否则我就隐藏"
            android:visibility="@{myModel.country.length() &lt; 1 ? android.view.View.VISIBLE : android.view.View.GONE}"/>

        <!--
            本例用于演示 @BindingAdapter 注解的用法
            app:imageUrl 的绑定数据由后台指定函数接管(注:通过 @{} 绑定的数据才会被接管)
        -->
        <ImageView
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:imageUrl='@{"https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"}'/>

    </LinearLayout>
</layout>

项目地址 https://github.com/webabcd/AndroidDemo
作者 webabcd

posted @ 2022-07-19 13:27  webabcd  阅读(173)  评论(0编辑  收藏  举报