如何在项目中封装 Kotlin + Android Databinding

简介: 如何在项目中封装 Kotlin + Android Databinding

image.png


在之前的文章 0xA05 Android 10 源码分析:Dialog 加载绘制流程以及在 Kotlin、DataBinding 中的使用 分析了 Dialog 加载绘制流程、设计模式,以及基于 DataBinding 封装的 DataBindingDialog 的基础库 JDataBinding,这篇文章主要讲基于 DataBinding 封装的基础库 JDataBinding


JDataBinding 源码地址:https://github.com/hi-dhl/JDataBinding


JDataBinding 是基于 DataBinding 封装的 DataBindingActivity、DataBindingFragment、DataBindingDialog、DataBindingListAdapter 基础库,欢迎 start


DataBinding 是什么?查看 Google官网,会有更详细的介绍


DataBinding 是 Google 在 Jetpack 中推出的一款数据绑定的支持库,利用该库可以实现在页面组件中直接绑定应用程序的数据源


利用 Kotlin 的 inline、reified、DSL 等等语法, 结合着 DataBinding,可以设计出更加简洁并利于维护的代码


DataBindingListAdapter



DataBindingListAdapter 是基于 ListAdapter 封装的,使用更少的代码快速实现 RecyclerView adapter and ViewHolder


什么是 ListAdapter?


ListAdapter 是 Google 推出的一个新的类库,相比传统的 Adapter,它能够用较少的代码实现更多的 RecylerView 的动画,并且可以自动存储之前的 list,ListAdapter 还加入了 DiffUtil 的工具类,只有当 items 变化的时候进行刷新,而不用刷新整个 list,大大提高 RecyclerView 的性能


什么是 DiffUtil?


DiffUtil 主要在后台计算 list 是否相同,然后回到回主线程刷新数据,主要用了 Myers Diff Algorithm, 而我们日常使用的 git diff 就用到了该算法


好了介绍完基础概念之后,来看一下 DataBindingListAdapter 是如何使用的,为什么我会说使用更少的代码快速实现 RecyclerView adapter and ViewHolder


Step1: 继承 BaseViewHolder


创建一个自定义的 ViewHolder 类,继承 DataBindingListAdapter,通过 viewHolderBinding 可以快速实现 DataBinding 的绑定


class TestViewHolder(view: View) : BaseViewHolder<Model>(view) {
    val binding: RecycieItemTestBinding by viewHolderBinding(view)
    override fun bindData(data: Model) {
        binding.apply {
            model = data
            executePendingBindings()
        }
    }
}


Step2: 继承 DataBindingListAdapter


实现带头部和尾部的 Adapter,创建自定义的 Adapter,继承 DataBindingListAdapter


class TestAdapter : DataBindingListAdapter<Model>(Model.CALLBACK) {
    override fun viewHolder(layout: Int, view: View): DataBindingViewHolder<Model> = when (layout) {
        R.layout.recycie_item_header -> HeaderViewHolder(view)
        else -> TestViewHolder(view)
    }
    override fun layout(position: Int): Int = when (position) {
        0 -> R.layout.recycie_item_header
        getItemCount() - 1 -> R.layout.recycie_item_footer
        else -> R.layout.recycie_item_test
    }
    override fun getItemCount(): Int = super.getItemCount() + 2
}


构造方法传入了 Model.CALLBACK,Model.CALLBACK 实现了 DiffUtil.ItemCallback,用于计算 list 的两个非空 item 的不同。具体要写两个抽象方法 areItemsTheSame 和 areContentsTheSame


val CALLBACK: DiffUtil.ItemCallback<Model> = object : DiffUtil.ItemCallback<Model>() {
            // 判断两个Objects 是否代表同一个item对象, 一般使用Bean的id比较
            override fun areItemsTheSame(oldItem: Model, newItem: Model): Boolean =
                oldItem.id == newItem.id
            // 判断两个Objects 是否有相同的内容。
            override fun areContentsTheSame(oldItem: Model, newItem: Model): Boolean = true
        }


Step3: 绑定 RecyclerView 和 Adapter


<data>
    <variable
        name="viewModel"
        type="com.hi.dhl.jdatabinding.demo.ui.MainViewModel" />
    <variable
        name="testAdapter"
        type="com.hi.dhl.jdatabinding.demo.ui.TestAdapter" />
</data>   
<androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:adapter="@{testAdapter}"
        app:adapterList="@{viewModel.mLiveData}"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />


这里用到了 DataBinding 的自定义数据绑定部分,可以百度、Google 具体的用法,具体实现可以参考 demo 下面 fragment_test.xml 文件


DataBindingDialog



在 Kotlin 中应该尽量避免使用构建者模式,使用 Kotlin 的具名可选参数构造类,实现构建者模式,代码更加简洁


在 "Effective Java" 书中介绍构建者模式时,是这样子描述它的:本质上 builder 模式模拟了具名的可算参数,就像 Ada和 Python中的一样


幸运的是,Kotlin 是一门拥有具名可选参数的变成语言,DataBindingDialog 在使用 Kotlin 的具名可选参数构造类实现 Dailog 构建者模式的基础上,用 DataBinding 进行二次封装,加上 DataBinding 数据绑定的特性,使 Dialog 变得更加简洁、易用


Step1: 继承 DataBindingDialog


class AppDialog(
    context: Context,
    val title: String? = null,
    val message: String? = null,
    val yes: AppDialog.() -> Unit
) : DataBindingDialog(context, R.style.AppDialog) {
    private val mBinding: DialogAppBinding by binding(R.layout.dialog_app)
    init {
        requireNotNull(message) { "message must be not null" }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requestWindowFeature(Window.FEATURE_NO_TITLE)
        mBinding.apply {
            setContentView(root)
            display.text = message
            btnNo.setOnClickListener { dismiss() }
            btnYes.setOnClickListener { yes() }
        }
    }
}


Step2: 简洁的调用方式


AppDialog(
        context = this@MainActivity,
        message = msg,
        yes = {
            // do something
        }).show()


DataBindingActivity



Kotlin 中的函数和构造器都支持具名可选参数,在使用上更加灵活,在  DataBindingActivity 中使用 Kotlin 的 inline、reified 强大的特性,将类型参数实化,初始化 View 更加简洁


继承 DataBindingActivity


class MainActivity : DataBindingActivity() {
    private val mBinding: ActivityMainBinding by binding(R.layout.activity_main)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding.apply {
            dialog.setOnClickListener {
                val msg = getString(R.string.dialog_msg)
                AppDialog(
                        context = this@MainActivity,
                        message = msg,
                        yes = {
                            Toast.makeText(this@MainActivity, msg, Toast.LENGTH_SHORT).show()
                        }).show()
            }
        }
    }
}


DataBindingFragment



在 Fragment 当中如何使用 Kotlin 的 inline、reified 初始化 View,可以查看DataBindingFragment


继承自 DataBindingFragment


class FragmentTest : DataBindingFragment() {
    val testViewModel: MainViewModel by viewModel()
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return binding<FragmentTestBinding>(
            inflater,
            R.layout.fragment_test, container
        ).apply {
            viewModel = testViewModel
            testAdapter = TestAdapter()
            lifecycleOwner = this@FragmentTest
        }.root
    }
}


关于基于 DataBinding 封装的 DataBindingActivity、DataBindingFragment、DataBindingDialog、DataBindingListAdapter 基础库,点击 JDataBinding 前往查看,欢迎start


JDataBinding 源码地址:https://github.com/hi-dhl/JDataBinding


参考文献



github.com/..BaseRecyc…


结语



致力于分享一系列 Android 系统源码、逆向分析、算法、翻译、Jetpack 源码相关的文章,正在努力写出更好的文章,如果这篇文章对你有帮助给个 star,文章中有什么没有写明白的地方,或者有什么更好的建议欢迎留言,欢迎一起来学习,在技术的道路上一起前进。


计划建立一个最全、最新的 AndroidX Jetpack 相关组件的实战项目 以及 相关组件原理分析文章,正在逐渐增加 Jetpack 新成员,仓库持续更新,可以前去查看:AndroidX-Jetpack-Practice, 如果这个仓库对你有帮助,请帮我点个赞,我会陆续完成更多 Jetpack 新成员的项目实践。


算法


由于 LeetCode 的题库庞大,每个分类都能筛选出数百道题,由于每个人的精力有限,不可能刷完所有题目,因此我按照经典类型题目去分类、和题目的难易程度去排序。


  • 数据结构: 数组、栈、队列、字符串、链表、树……
  • 算法: 查找算法、搜索算法、位运算、排序、数学、……


每道题目都会用 Java 和 kotlin 去实现,并且每道题目都有解题思路、时间复杂度和空间复杂度,如果你同我一样喜欢算法、LeetCode,可以关注我 GitHub 上的 LeetCode 题解:Leetcode-Solutions-with-Java-And-Kotlin,一起来学习,期待与你一起成长。


Android 10 源码系列


正在写一系列的 Android 10 源码分析的文章,了解系统源码,不仅有助于分析问题,在面试过程中,对我们也是非常有帮助的,如果你同我一样喜欢研究 Android 源码,可以关注我 GitHub 上的 Android10-Source-Analysis,文章都会同步到这个仓库。



工具系列



逆向系列




目录
相关文章
|
6天前
|
Java 数据库 Android开发
【专栏】构建高效 Android 应用:探究 Kotlin 多线程优化策略
【4月更文挑战第27天】本文探讨了Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理。通过案例分析展示了网络请求、图像处理和数据库操作的优化实践。同时,文章指出并发编程的挑战,如性能评估、调试及兼容性问题,并强调了多线程优化对提升应用性能的重要性。开发者应持续学习和探索新的优化策略,以适应移动应用市场的竞争需求。
|
2天前
|
移动开发 Java Android开发
构建高效Android应用:Kotlin协程的实践之路
【4月更文挑战第30天】在移动开发领域,随着用户需求的不断增长和设备性能的持续提升,实现流畅且高效的用户体验已成为开发者的首要任务。针对Android平台,Kotlin协程作为一种新兴的异步编程解决方案,以其轻量级线程管理和简洁的代码逻辑受到广泛关注。本文将深入探讨Kotlin协程的概念、优势以及在实际Android应用中的运用,通过实例演示如何利用协程提升应用性能和响应能力,为开发者提供一条构建更高效Android应用的实践路径。
|
2天前
|
缓存 安全 Android开发
构建高效Android应用:采用Kotlin进行内存优化
【5月更文挑战第1天】随着移动设备的普及,用户对应用程序的性能要求越来越高。特别是对于Android开发者来说,理解并优化应用的内存使用是提升性能的关键。本文将探讨使用Kotlin语言在Android开发中实现内存优化的策略和技术。我们将深入分析Kotlin特有的语言特性和工具,以及它们如何帮助开发者减少内存消耗,避免常见的内存泄漏问题,并提高整体应用性能。
|
2天前
|
安全 Android开发 开发者
构建高效Android应用:采用Kotlin与Jetpack的实践指南
【4月更文挑战第30天】 在移动开发领域,随着技术的不断进步,为了提高应用的性能和用户体验,开发者们不断地探索新的工具和框架。对于Android平台而言,Kotlin语言以其简洁性和功能性成为了开发的首选。而Jetpack组件则提供了一套高质量的库、工具和指南,帮助开发者更轻松地构建高质量的应用程序。本文将探讨如何结合Kotlin语言和Jetpack组件来优化Android应用的开发流程,提升应用性能,并保证代码的可维护性和可扩展性。
|
2天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第30天】在Android开发领域,Kotlin作为一种现代化的编程语言,因其简洁性和功能性受到了开发者的广泛欢迎。尽管与传统的Java相比,Kotlin提供了诸多便利,但关于其性能表现的讨论始终未息。本文将深入分析Kotlin和Java在Android平台上的性能差异,通过实际测试数据揭示两种语言在编译效率、运行速度以及内存占用方面的具体表现,并探讨如何利用Kotlin的优势来提升Android应用的整体性能。
|
2天前
|
移动开发 调度 Android开发
构建高效Android应用:Kotlin协程的实践之路
【4月更文挑战第30天】 在移动开发领域,性能优化与流畅的用户体验始终是开发者追求的目标。随着Kotlin语言在Android开发中的普及,其提供的协程特性成为了解决异步编程问题的有力工具。本文将通过深入分析Kotlin协程的原理与实践,展示如何在Android应用中利用协程提升响应速度和处理效率,同时保证代码的简洁性和可维护性。我们将从基本概念出发,逐步深入到协程的高级使用场景,帮助开发者构建更加高效的Android应用。
|
3天前
|
算法 安全 Android开发
深入理解操作系统的内存管理机制构建高效Android应用:Kotlin的协程优势
【4月更文挑战第30天】 在现代计算机系统中,操作系统的内存管理是确保系统高效、稳定运行的关键。本文将探讨操作系统内存管理的核心技术,包括内存分配、虚拟内存、分页和分段等概念,以及它们是如何协同工作以提高内存利用率和系统性能的。通过对这些技术的详细分析,我们可以更好地理解操作系统背后的原理,并评估不同内存管理策略对系统行为的影响。 【4月更文挑战第30天】 在移动开发领域,尤其是针对Android平台,性能优化和流畅的用户体验始终是开发者追求的核心目标。随着Kotlin语言的普及,协程作为其在异步编程领域的杀手锏特性,已经逐渐成为提高应用性能和简化代码结构的重要工具。本文将深入探讨Kotli
|
3天前
|
移动开发 调度 Android开发
构建高效Android应用:Kotlin协程的实践与优化
【4月更文挑战第30天】在移动开发领域,性能和响应性是衡量应用质量的关键指标。对于Android平台而言,Kotlin协程作为一种新兴的异步编程解决方案,提供了更为简洁和高效的处理并发任务的能力。本文将深入探讨Kotlin协程的核心原理,以及如何通过它们来提升Android应用的性能。我们将从基础概念出发,逐步介绍协程的创建、管理以及与Android UI线程的交互,并最终展示如何优化现有代码以利用协程的优势。
|
3天前
|
数据库 Android开发 开发者
构建高效Android应用:采用Kotlin与Jetpack的实践指南
【4月更文挑战第30天】 随着移动开发技术的不断演进,Android平台提供了多种工具和框架以提升应用性能和开发效率。在本文中,我们将深入探讨如何结合Kotlin语言的简洁性和Android Jetpack组件的强大功能来构建一个既高效又可维护的Android应用。通过分析现代Android应用架构的关键要素,我们将展示如何利用Kotlin的特性以及如何整合Jetpack中的LiveData、ViewModel和Room等组件,以实现响应式编程、数据持久化和生命周期管理。
|
4天前
|
移动开发 数据库 Android开发
构建高效Android应用:探究Kotlin协程的优化实践
【4月更文挑战第29天】在移动开发领域,尤其是Android平台上,性能优化一直是开发者关注的重点。近年来,Kotlin语言凭借其简洁性和功能性成为Android开发的热门选择。其中,Kotlin协程作为一种轻量级的并发处理机制,为编写异步代码、网络请求和数据库操作提供了极大的便利。本文将深入探讨Kotlin协程在Android应用中的性能优化技巧,帮助开发者构建更加高效的应用程序。