JetpackDataBinding 架构组件 ④ ( 使用 @BindingAdapter 注解为布局组件绑定自定义逻辑 | 网络图片加载 | 本地图片加载 )

Posted 韩曙亮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JetpackDataBinding 架构组件 ④ ( 使用 @BindingAdapter 注解为布局组件绑定自定义逻辑 | 网络图片加载 | 本地图片加载 )相关的知识,希望对你有一定的参考价值。

文章目录





一、@BindingAdapter 注解



BindingAdapter DataBinding 数据绑定技术 的组成部分 ;


1、注解简介


借助 @BindingAdapter 注解 可以 将自定义逻辑 绑定到 DataBinding 布局中 ;


在 DataBinding 布局中 , 不只是机械性的显示内容 或者 拼接内容 , 还需要 进行更复杂的操作 ;

如 : 为 ImageView 组件绑定数据模型 , 传入一个 url 网络图片地址 , 在该组件中显示网络图片 , 如果网络图片加载失败或者为空 , 则加载默认的本地资源 ;

上述操作必须 自定义一段代码逻辑进行实现 , 使用简单的数据绑定无法实现该功能 ;


2、使用 @BindingAdapter 注解为布局组件绑定自定义逻辑


首先 , 启用 DataBinding , 在 DataBinding 数据绑定 布局中 引入 绑定的数据模型 ;

    <data>
        <variable
            name="变量名"
            type="变量类型" />
    </data>

然后 , 在 DataBinding 布局中 , 为组件的 app:注解参数 属性设置 "@变量名" 属性值 ; 该属性名称 注解参数 就是使用 @BindingAdapter("注解参数") 注解修饰的 Java 静态函数 ;

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:注解参数="@变量名"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.2"/>

最后 , 定义 BindingAdapter 静态方法 , 该静态方法使用 @BindingAdapter 注解修饰 , 方法的参数就是 @变量名 类型的参数 ;

  • 该方法中第一个参数是 布局中的组件
  • 第二个参数是 DataBinding 布局中 绑定的 数据模型
        @JvmStatic
        @BindingAdapter("注解参数")
        fun setImage(组件参数名称: 组件类型, 绑定变量名: 变量类型) 
            // 绑定的代码逻辑
        

注解参数 DataBinding 布局中的组件 app:注解参数 属性名称 对应 ;

DataBinding 布局中的 变量名 组件 app:注解参数 属性值 对应 ;





二、使用 @BindingAdapter 注解绑定加载网络图片静态方法



在 DataBinding 布局中 , 绑定数据模型 ;

    <data>
        <variable
            name="imageNetwork"
            type="String" />
    </data>

在 ImageView 组件中 , 设置 app:image="@imageNetwork" 属性 , imageNetwork 是绑定的数据 ;

app:image 属性 , 对应着 @BindingAdapter("image") 注解中的 注解参数 image ;

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:image="@imageNetwork"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.2"/>

在 Kotlin 中 , 定义 Java 静态方法 , 需要在 companion object 伴生对象 中 , 使用 @JvmStatic 修饰函数 ;

使用 @BindingAdapter("image") 修饰函数 , 其中的注解参数 image 对应组件中的 app:image 属性 ;

imageView: ImageView 参数是 DataBinding 布局中的 被绑定的组件 ;

url: String 参数是 DataBinding 布局中绑定的数据模型 ;

class ImageViewBindingAdapter 
    companion object 
        /*
            DataBinding 布局中 ImageView 适配器
             - imageView: ImageView 参数就是布局中的 ImageView
             - url: String 参数是 ImageView 的 app:image 属性值
                 - app:image="@imageNetwork"
                 - imageUrl 该值是 <data> 标签中的 variable , 类型为 String

            <data>
                <variable
                    name="imageNetwork"
                    type="String" />
            </data>
         */
        @JvmStatic
        @BindingAdapter("image")
        fun setImage(imageView: ImageView, url: String) 
            // 加载网络图片
            if (!TextUtils.isEmpty(url)) 
                Picasso.get().load(url).into(imageView);
             else 
                imageView.setBackgroundColor(Color.GREEN)
            
        
	

在 Activity 组件中 , 向 DataBinding 布局中设置 imageNetwork 数据模型的对象 ;

        // 设置布局文件
        // 布局文件是 activity_main.xml
        // 该类名称生成规则是 布局文件名称 + Binding
        var activityMainBinding: ActivityMainBinding =
            DataBindingUtil.setContentView(this, R.layout.activity_main)

        // 为布局 设置 数据
        activityMainBinding.imageNetwork = "https://img-blog.csdnimg.cn/0d611b315e8448f7a01f7a772c238c6f.png"




三、使用 @BindingAdapter 注解绑定加载本地图片静态方法



在 DataBinding 布局中 , 绑定数据模型 ;

    <data>
        <variable
            name="imageLocal"
            type="int" />
    </data>

在 ImageView 组件中 , 设置 app:image="@imageLocal" 属性 , imageLocal 是绑定的数据 ;

app:image 属性 , 对应着 @BindingAdapter("image") 注解中的 注解参数 image ;

        <ImageView
            android:id="@+id/imageView2"
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:image="@imageLocal"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.4"/>

在 Kotlin 中 , 定义 Java 静态方法 , 需要在 companion object 伴生对象 中 , 使用 @JvmStatic 修饰函数 ;

使用 @BindingAdapter("image") 修饰函数 , 其中的注解参数 image 对应组件中的 app:image 属性 ;

imageView: ImageView 参数是 DataBinding 布局中的 被绑定的组件 ;

resourceId: Int 参数是 DataBinding 布局中绑定的数据模型 ;

class ImageViewBindingAdapter 
    companion object 
        /*
            DataBinding 布局中 ImageView 适配器
             - imageView: ImageView 参数就是布局中的 ImageView
             - resourceId: Int 参数是 ImageView 的 app:image 属性值
                 - app:image="@imageLocal"
                 - imageLocal 该值是 <data> 标签中的 variable , 类型为 int

            <data>
                <variable
                    name="imageLocal"
                    type="int" />
            </data>
         */
        @JvmStatic
        @BindingAdapter("image")
        fun setImage(imageView: ImageView, resourceId: Int) 
            imageView.setImageResource(resourceId)
        
	

在 Activity 组件中 , 向 DataBinding 布局中设置 imageNetwork 数据模型的对象 ;

        // 设置布局文件
        // 布局文件是 activity_main.xml
        // 该类名称生成规则是 布局文件名称 + Binding
        var activityMainBinding: ActivityMainBinding =
            DataBindingUtil.setContentView(this, R.layout.activity_main)

        // 为布局 设置 数据
        activityMainBinding.imageLocal = R.mipmap.ic_launcher




四、使用 @BindingAdapter 注解绑定加载网络图片或本地图片静态方法



在 DataBinding 布局中 , 绑定数据模型 ;

    <data>
        <variable
            name="imageNetwork"
            type="String" />

        <variable
            name="imageLocal"
            type="int" />
    </data>

在 ImageView 组件中 ,

设置 app:image="@imageNetwork" 属性 , imageNetwork 是绑定的数据 ;

设置 app:imageDefaultRes="@imageLocal"" 属性 , imageLocal 是绑定的数据 ;

app:image 属性 , 对应着 @BindingAdapter("image") 注解中的 注解参数 image ;

        <ImageView
            android:id="@+id/imageView3"
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:image="@imageNetwork"
            app:imageDefaultRes="@imageLocal"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.6"/>

在 Kotlin 中 , 定义 Java 静态方法 , 需要在 companion object 伴生对象 中 , 使用 @JvmStatic 修饰函数 ;

使用 @BindingAdapter(value = ["image", "imageDefaultRes"], requireAll = false) 修饰函数 ,

  • 其中的注解参数 value = ["image", "imageDefaultRes"] 对应组件中的 app:imageapp:imageDefaultRes"属性 ;
  • requireAll = false 表示这两个注解属性 , 不是必须都齐全的 , 可以设置任意一个 , 也可以都设置 ;

imageView: ImageView 参数是 DataBinding 布局中的 被绑定的组件 ;

url: String 参数是 DataBinding 布局中绑定的数据模型 ;

        <variable
            name="imageNetwork"
            type="String" />

resourceId: Int 参数是 DataBinding 布局中绑定的数据模型 ;

        <variable
            name="imageLocal"
            type="int" />
class ImageViewBindingAdapter 
    companion object 
        /*
            DataBinding 布局中 ImageView 适配器
             - imageView: ImageView 参数就是布局中的 ImageView
             - url: String 参数是 ImageView 的 app:image 属性值
                 - app:image="@imageNetwork"
                 - imageUrl 该值是 <data> 标签中的 variable , 类型为 String
             - resourceId: Int 参数是 ImageView 的 app:image 属性值
                 - app:image="@imageLocal"
                 - imageLocal 该值是 <data> 标签中的 variable , 类型为 int

            <data>
                <variable
                    name="imageNetwork"
                    type="String" />

                <variable
                    name="imageLocal"
                    type="int" />
            </data>

            注意 : 如果是 Java 静态函数 , 注解为
            @BindingAdapter(value = ["image", "imageDefaultRes"], requireAll = false)
            Kotlin 中使用 [] 初始化数组 , Java 中使用  初始化数组
         */
        @JvmStatic
        @BindingAdapter(value = ["image", "imageDefaultRes"], requireAll = false)
        fun setImage(imageView: ImageView, url: String, resourceId: Int) 
            // 加载网络图片
            if (!TextUtils.isEmpty(url)) 
                Picasso.get().load(url).into(imageView);
             else 
                imageView.setImageResource(resourceId)
            
        
	

在 Activity 组件中 , 向 DataBinding 布局中设置 imageNetwork 数据模型的对象 ;

        // 设置布局文件
        // 布局文件是 activity_main.xml
        // 该类名称生成规则是 布局文件名称 + Binding
        var activityMainBinding: ActivityMainBinding =
            DataBindingUtil.setContentView(this, R.layout.activity_main)

        // 为布局 设置 数据
        activityMainBinding.imageLocal = R.mipmap.ic_launcher




五、完整代码示例




1、build.gradle 构建脚本


plugins 
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'


android 
    namespace 'kim.hsl.databinding_demo'
    compileSdk 32

    defaultConfig 
        applicationId "kim.hsl.databinding_demo"
        minSdk 21
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        // 启用 DataBinding
        dataBinding 
            enabled = true
        
    

    buildTypes 
        release 
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        
    
    compileOptions 
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    
    kotlinOptions 
        jvmTarget = '9'
    


dependencies 
    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

    implementation 'com.squareup.picasso:picasso:2.71828'


2、AndroidManifest.xml 清单文件


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

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.DataBinding_Demo"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>

</manifest>

3、DataBinding 布局文件


<?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="imageNetwork"
            type="String" />

        <variable
            name="imageLocal"
            type="int" />
    </data>

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

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:image="@imageNetwork"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.2"/>

        <ImageView
            android:id="@+id/imageView2"
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:image="@imageLocal"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.4"/>

        <ImageView
            android:id="@+id/imageView3"
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:image="@imageNetwork"
            app:imageDefaultRes="@imageLocal"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:la

工业防火墙架构与技术第二节:硬件架构④


下图展示了主板的主电源供电电路设计图:

技术分享

下图展示了基于主供电电源的以太网、现场总线、以及485总线需要的电源隔离电路设计图。

技术分享

除此之外,既然断电也是一种可能存在的单点故障,那么在硬件架构设计的时候,本身工业主板的供电还应该考虑的是双备电源电路设计!也就是冗余电源。下图展示了工业主板针对的双备电源电路设计设计图:

技术分享

因此工业防火墙在硬件架构设计上需要考虑冗余电源供电,当其中一路电源出现故障时,另外一路电源仍然能够保障防火墙的正常工作,同时需要设计中很短的时间之内将电源的故障进行报警,以使得维修人员及时维修。对于电源的供电技术,出了在电路上设计双冗余设计外,还可以采用POE供电技术。

除了Bypass功能的物理之间导通以及供电上的冗余设计考虑外,遇到突发情况时抗冲击能力和其他性能同样非常重要,比如受到外力冲击,即使遭受到不法分子的蓄意破坏,工业防火墙也能够完好无损并稳定工作。

另外,工业防火墙区别于传统防火墙的另外一点是,工业防火墙会设计支持工业现场总线协议以及RS232RS485总线协议的接口。在工业控制、电力通讯、智能仪表等领域,通常情况下是采用串口通信的方式进行数据交换。最初采用的方式是 RS232 接口,由于工业现场比较复杂,各种电气设备会在环境中产生比较多的电磁干扰,会导致信号传输错误。除此之外,RS232 接口只能实现点对点通信,不具备联网功能,最大传输距离也只能达到十几米,不能满足远距离通信要求。而 RS485 则解决了这些问题,数据信号采用差分传输方式,可以有效的解决共模干扰问题,最大距离可达 1200 米,并且允许多个收发设备接到同一条总线上。随着工业应用通信越来越多,1979年施耐德电气制定了一个用于工业现场的总线协议 Modbus 协议,现在工业中使用RS485 通信场合很多都采用 Modbus 协议。因此在RS485 通信场合,工业防火墙还得支持基于RS485总线协议的防护,要支持RS485总线协议,就必须添加串口模块,从而编写RS总线接口电路设计图,如下图所示就是一个典型的RS485总线电路设计图:

技术分享

技术分享

以往,PC与智能设备通讯多借助RS232RS485、以太网等方式,主要取决于设备的接口规范。但RS232RS485只能代表通讯的物理介质层和链路层,如果要实现数据的双向访问,就必须自己编写通讯应用程序,但这种程序多数都不能符合ISO/OSI的规范,只能实现较单一的功能,适用于单一设备类型,程序不具备通用性。在RS232RS485设备联成的设备网中,如果设备数量超过2台,就必须使用RS485做通讯介质,RS485网的设备间要想互通信息只有通过“主(Master)”设备中转才能实现,这个主设备通常是PC,而这种设备网中只允许存在一个主设备,其余全部是从(Slave)设备。而现场总线技术是以ISO/OSI模型为基础的,具有完整的软件支持系统,能够解决总线控制、冲突检测、链路维护等问题。现场总线设备自动成网,无主/从设备之分或允许多主存在。在同一个层次上不同厂家的产品可以互换,设备之间具有互操作性。CAN协议是这种现场总线协议的代表和应用最广泛的协议。CAN-BusController Area Network)即控制器局域网,是国际上应用最广泛的现场总线之一。起先,CAN-bus被设计作为汽车环境中的微控制器之间通讯,在车载各电子控制装置ECU之间交换信息,形成汽车电子控制网络。它是一种多主方式的串行通讯总线,基本设计规范要求有较高的位速率,高抗干扰性,而且能够检测出产生的任何错误。信号传输距离达到10Km时,仍然可提供高达5Kbps的数据传输速率。由于CAN串行通讯总线具有这些特性,它很自然的在汽车、制造业以及航空工业中受到广泛应用。由于CAN现场总线协议应用的广泛性以及现在住工业环境中所处的地位,工业防火墙的设计还必须考虑对其的支持。下图显示了工业防火墙在主板上,对现场总线协议驱动设计的实现电路,其分为驱动芯片和控制芯片:

技术分享

总结:基于工业级的防火墙,首先需要满足工业环境对硬件的要求,硬件设计考虑就必须按照工业级的标准进行设计;同时还需要考虑工业级对网络处理实时性的要求,硬件设计就得考虑采用更合理的处理架构更快的在硬件层面实现数据包处理的实时性;此外基于工业级对稳定性的要求,工业级防火墙还得考虑Bypass旁路保护功能以及双路供电等尽量满足稳定性要求的设计。除外,工业级防火墙本身的高可用HA功能也是必须要考虑的。这个功能目前就调研的大部分防火墙设计来看,大部分基于软件层面实现,很少有基于硬件层面来实现设备的高可用功能。


本文出自 “我拿流年乱了浮生” 博客,请务必保留此出处http://tasnrh.blog.51cto.com/4141731/1919032

以上是关于JetpackDataBinding 架构组件 ④ ( 使用 @BindingAdapter 注解为布局组件绑定自定义逻辑 | 网络图片加载 | 本地图片加载 )的主要内容,如果未能解决你的问题,请参考以下文章

JetpackDataBinding 架构组件 ( 数据绑定技术简介 | Android 中的 DataBinding 数据绑定 | 启动数据绑定 | 定义数据类 | 布局文件转换 )

JetpackLifecycle 架构组件 ( 系统组件与普通组件解耦 | Lifecycle 解耦系统组件与普通组件 | 解耦服务组件与普通组件 | 监听应用程序生命周期 )

软考 系统架构设计师软件架构设计④ 基于架构的软件开发方法

软考 系统架构设计师案例分析④ 软件架构风格

工业防火墙架构与技术第二节:硬件架构④

架构师带你面试④Java虚拟机(JVM)面试题2020