Google挖坑后人埋-ViewBinding(上)

官网镇楼

https://developer.android.com/topic/libraries/view-binding

官方警告

Warning: The 'kotlin-android-extensions' Gradle plugin is deprecated. Please use this migration guide (https://goo.gle/kotlin-android-extensions-deprecation) to start working with View Binding (https://developer.android.com/topic/libraries/view-binding) and the 'kotlin-parcelize' plugin.

kotlin-android-extensions是个好东西,可以帮我们省掉很多需要写findViewById的场景。相信大部分的Kotlin开发者都在使用它进行Android开发,而且在之前的Android Studio创建Android项目时,都会自动帮你依赖:

apply plugin: 'kotlin-android-extensions'

但是现在你再创建Android项目,就不会自动帮你依赖了,其原因就是kotlin-android-extensions这个插件已经被废弃了。

为啥?Google这新技术迭代跟玩一样啊,有kotlin-android-extensions插件我不用,我就手写,哎,就是玩儿~

其实,kotlin-android-extensions插件还是有很多问题的,虽然它很方便,但实际上,这是牺牲掉一部分内存来换取的方便,在对应用性能日益严格的今天,这种做法势必会被淘汰掉。

kotlin-android-extensions三宗罪

内存问题

通过反编译kotlin-android-extensions的代码,你就会发现,通过kotlin-android-extensions,它会在代码中创建一个HashMap,用来存放所有的id和对应的View的缓存,如果缓存中没有需要的View,那么就通过findViewById去创建,否则就直接获取,这就是它的原理。

资源ID重名

由于kotlin-android-extensions是通过view的id名直接引用的,所以多个布局间的同名id,就需要手动对import进行重命名处理,而且经常会引用错误的布局文件,导致运行崩溃。

Kotlin only

只有Kotlin才可以使用。

当然,ViewBinding也不是银弹,对比kotlin-android-extensions,它也有一些问题:

  • 使用比kotlin-android-extensions复杂

  • 依然有需要手动处理的场景

当然也有一些优势:

  • Kotlin Java通吃

  • 空安全

ViewBinding初步

ViewBinding就是为了解决kotlin-android-extensions的这些使用问题而诞生的,它的目的只有一个,那就是避免重复的findViewById的同时,不影响应用性能。

要使用ViewBinding非常简单:

buildFeatures {
    viewBinding true
}

当我们开启ViewBinding之后,在编译时,AGP会自动帮我们给每个xml布局创建一个Binding类,Binding类的命名规则是将xml文件按驼峰方式重命名后,再加上Binding作为结尾得到的,例如splash_layout.xml会自动生成一个SplashLayoutBinding的类文件。

跨Module使用的时候,子Module也需要开启ViewBinding功能

这个Binding文件,实际上就相当于kotlin-android-extensions的HashMap,同时由于它在编译时就生成了,就不会占用运行时内存。

虽然这里生成了大量的XXXBinding文件,但是对编译速度的影响和生成Apk大小的影响几乎可以忽略:

  • 未使用的XXXBinding文件会在混淆时被删除

  • 编译器生成Binding文件的速度极快,同时是增加更新

ignore

如果你不想生成这个Binding类,可以通过下面的方式来过滤掉该文件的生成。

<FrameLayout
    xmlns:tools="http://schemas.android.com/tools"
    ...
    tools:viewBindingIgnore="true">
    ...
</FrameLayout>

使用

开启ViewBinding后,会给xml布局生成XXXBinding文件,位于build/generated/data_binding_base_class_source_out/目录下。

Activity

在Activity中使用ViewBinding一般需要使用到Binding类的inflate方法,一般使用方式如下所示。

private val binding by lazy { XxxBinding.inflate(layoutInflater) }

binding.TitleTextView.text = "Title"

Binding类还有一个getRoot方法,用来返回xml布局的根元素,所以setContentView(R.layout.xxxx)就可以替换为:

setContentView(binding.root)

Fragment

在Fragment中使用ViewBinding会比在Activity中使用要复杂一点,因为需要保证Binding类与Fragment的生命周期同步,示例代码如下所示。

class MainFragment : Fragment() {

    private var _binding: OutcircleMissionFansGroupBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        _binding = OutcircleMissionFansGroupBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

_binding和binding傻傻分不清吗?其实没什么区别,这是为了在Kotlin中将不可空类型置空的一种妥协方式,同样的代码逻辑,在Java中,就会非常简单了。

public class MainFragment extends Fragment {

    private FragmentMainBinding binding;

    @Override
    public View onCreateView(@NotNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        binding = FragmentMainBinding.inflate(inflater, container, false);
        return binding.getRoot();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}

Adapter

除了Activity和Fragment,在Adapter中使用,特别是RecyclerView中使用,也是一个非常常见的使用场景。利用kotlin-android-extensions,我们可以借助LayoutContainer来在ViewHolder中直接使用View id,那么在ViewBinding中,使用方式就更简单了。

class DemoAdapter(val dataList: List<String>) : RecyclerView.Adapter<DemoAdapter.ViewHolder>() {

    inner class ViewHolder(binding: OutcircleMissionFansGroupBinding) : RecyclerView.ViewHolder(binding.root) {
        val title: TextView = binding.titleTextView
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = OutcircleMissionFansGroupBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val data = dataList[position]
        holder.title.text = data.title
    }

    override fun getItemCount() = dataList.size
}

其实核心代码依然是inflate,套路都是一样的。

Dialog

原理依然是一个套路。

override fun onCreate(savedInstanceState: Bundle?) {
    binding = XXXXBinding.inflate(layoutInflater)
    setContentView(binding.root)
}

Include、Merge

在布局中通过include来引入新的布局也是一个很常用的方式,kotlin-android-extensions由于底层使用的是运行时findViewById,所以不会存在什么问题,但是ViewBinding就不一样了,由于它是编译时生成,所以需要指定id才可以使用。

因此,在ViewBinding中使用include的layout,有两种方式,一种是给include设置id,这样通过id就可以直接引用,代码如下所示。

<include 
        android:id="@+id/xxxxx"
        layout="@layout/xxxxxxx" />

这样使用的时候,代码如下:

XXXBinding.xxxInclude.xxxx

另外一种方式是直接使用新的Binding文件,因为所有的xml布局文件都会生成Binding,所以可以直接使用这个Binding文件。

IncludeXXXXXBinding.bind(binding.root).xxxxx

这种方式还可以解决Merge的引入问题。

迁移

更新一时爽,迁移火葬场。

目前还未找到现有项目从kotlin-android-extensions迁移到ViewBinding的好办法,如果当前的项目大量使用kotlin-android-extensions,那么迁移起来,就是一个巨大的工程,没有migration tools,也不能通过脚本更换,确实没找到什么好的办法。

向大家推荐下我的网站 https://xuyisheng.top/  点击原文一键直达

专注 Android-Kotlin-Flutter 欢迎大家访问

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: ViewBinding和DataBinding都是Android开发中的数据绑定框架,它们可以将布局文件中的视图与代码中的变量绑定起来,从而方便地操作视图和数据。 ViewBindingAndroid官方在Android Studio 3.6中推出的一个新特性,它通过生成一个与布局文件对应的绑定类来实现视图绑定,可以避免findViewById的繁琐操作,提高代码的可读性和可维护性。 DataBindingGoogleAndroid Studio 1.3中推出的一个数据绑定框架,它可以将数据与视图绑定起来,实现双向绑定,从而简化了代码的编写和维护。使用DataBinding可以将视图的属性和数据模型的属性绑定起来,当数据模型的属性发生变化时,视图会自动更新,反之亦然。 总的来说,ViewBinding适用于简单的视图绑定场景,而DataBinding则适用于更复杂的数据绑定场景。 ### 回答2: ViewBinding和DataBinding都是Android中的数据绑定库。它们旨在使应用程序中的 UI 和逻辑分离,同时还可以减少模板化代码。虽然它们都执行类似的任务,但它们之间存在一些区别。 首先,ViewBinding是针对单个视图文件生成绑定类。这样,在绑定代码中,您只能访问单个视图。因此,ViewBinding的代码量要比DataBinding少。 相比而言,DataBinding要复杂一些。 DataBinding不仅可用于绑定单个视图,还可用于绑定整个布局层次结构。它需要实现一整套工具来使数据绑定的代码与布局文件相对应。 其次,ViewBinding是使用annotation处理器生成绑定类的方式实现数据绑定,这意味着它可以相对快速地编译布局文件。另一方面,DataBinding需要生成额外的 Java 代码和一些 XML 文件来实现数据绑定,这使编译时间更长。 但是,DataBinding可以使用双向绑定技术,这意味着数据的变化可以直接反映到视图中。这使得在处理表单输入等特定场景时使用DataBinding会更容易一些。 总体而言,ViewBinding是更简单的选择,适合较小的项目,而DataBinding则更为复杂,适合需要大规模数据绑定的项目。它们都是可用的解决方案,您可以根据需求进行选择。 ### 回答3: ViewBinding和DataBindingAndroid中的两种视图绑定库。两者的共同点是都可以通过自动生成的绑定类来实现视图的绑定,从而避免了findViewById的繁琐操作;不同点在于ViewBinding的目的是简化视图绑定,而DataBinding则可以实现更复杂的数据绑定和数据处理。 ViewBinding的主要作用是消除繁琐的findViewById操作,并且能够更好地保证类型安全。使用ViewBinding,我们只需要在需要进行视图绑定的Activity或Fragment中引入绑定类,然后通过绑定类实例来访问布局文件中所包含的所有控件。ViewBinding使用起来非常简单,只需要在build.gradle中添加如下配置即可: android { ... viewBinding { enabled = true } } 使用ViewBinding的代码示例: private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.textView.text = "Hello ViewBinding" } 对于DataBinding而言,它能够更好地实现数据绑定和数据处理,可以使用表达式将数据绑定到视图上,进行数据转换和格式化,从而实现更灵活的UI界面。使用DataBinding需要在build.gradle中添加如下配置: android { ... dataBinding { enabled = true } } 使用DataBinding的代码示例: <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.example.User" /> </data> <LinearLayout ... > <TextView ... android:text="@{user.name}" /> <TextView ... android:text="@{user.age,StringFormat}" /> <Button ... android:onClick="@{() -> user.onButtonClick()}" android:text="@{user.buttonText}" /> </LinearLayout> </layout> DataBinding可以更好地实现MVC中的数据与视图分离,也可以通过ViewModel和LiveData等技术实现MVVM模式。在使用DataBinding开发过程中,需要注意避免过于复杂的绑定表达式和数据转换等操作,以及注意内存泄漏的问题。 总的来说,ViewBinding和DataBinding都是非常有用的Android开发库,可以根据具体的需求来选择使用哪种库,在提高开发效率的同时也能提升应用程序的性能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值