添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
风度翩翩的柿子  ·  Scope functions | ...·  3 周前    · 
开朗的枇杷  ·  Java ...·  1 月前    · 
眼睛小的铅笔  ·  Windows XML Event Log ...·  1 月前    · 
失望的苹果  ·  OS操作系统 - 研华·  2 月前    · 

原文:[Migrating the deprecated Kotlin Android Extensions compiler plugin](https://proandroiddev.com/migrating-the-deprecated-kotlin-android- extensions-compiler-plugin-to-viewbinding-d234c691dec7)
作者:[Ahmad El-Melegy](https://melegy.medium.com/?source=post_page----- d234c691dec7--------------------------------)

Kotlin 1.4.20-M2 中,JetBrains废弃了 Kotlin Android Extensions编译插件。

其实这是早就预料到的,你可以在这次[提交](https://android- review.googlesource.com/c/platform/frameworks/support/+/882241)中看到详情。

kotlinx.android.synthetic不再是一个推荐的做法。删除了显式的findViewById。

但为什么呢?

kotlinx的合成属性存在一些众所周知的问题。

  • 它公开了以view的id为名的全局变量,但该名称与实际的布局无关,没有针对无效查找进行检查。
  • 它只适用于Kotlin。
  • 当View只存在于某些配置中时,它们没有空安全提示。
  • 所有这些问题加在一起,导致增加了Android应用的崩溃次数。
  • 另外谷歌正在推广模块化,但合成属性不能跨模块工作。这是自2018年1月以来的一个 公开问题
  • 有哪些替代方案?

  • [View Binding](https://developer.android.google.cn/topic/libraries/view- binding/)是视图查找以及绑定的推荐方案,但与Android Kotlin Extensions相比,它确实增加了一些开销。但它增加了编译时对视图查找的检查和类型安全。
  • 传统方式findViewById,Kotlin和Java都适用。
  • JetBrains废弃了Kotlin Android Extensions,推荐使用View Binding,所以我们将在本文中探讨如何迁移到View Binding。

    View Binding

    不要与Data Binding混淆

    View Binding 是一种功能,它允许您更容易地编写与视图交互的代码。

    一旦在一个模块中启用了 View Binding ,它就会为该模块中存在的每个 XML 布局文件生成一个绑定类。

    绑定类的实例包含对相应布局中具有ID的所有VIew的直接引用。

    View Binding 对于在多个配置中定义的布局来说是Null-safe的。

    View Binding 将检测视图是否只存在于某些配置中,并创建一个 @Nullable 属性。

    View Binding 适用于Java和Kotlin。

    如何启用View Binding?

    你不需要添加任何额外的库来启用 View Binding 。从Android Studio 3.6版本开始,它就被内置到Android Gradle Plugin中了。如果要在模块中启用该功能,请在你的 build.gradle 文件中添加以下内容。

    android {
        buildFeatures {
            viewBinding true
    

    如何使用View Binding?

    如果为模块启用了View Binding,则会为模块包含的每个 XML 布局文件生成一个绑定类。

    每个绑定类都包含对根视图和所有具有ID的视图的引用。

    绑定类的名称是通过将 XML 文件的名称转换为驼峰式大小写,并在结尾处添加 Binding 一词来生成的。

    译者注:例如,假设某个布局文件的名称为 result_profile.xml,所生成的绑定类的名称就为 ResultProfileBinding

    在Activity中使用View Binding

    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
    

    然后可以使用binding对象访问视图:

    binding.name.text = "Some Text"
    

    在Fragment中使用View Binding

    Fragment中使用View Binding需要多加注意,如果使用不当它会引发内存泄漏,如果你没有在onDestroy中将view置空,那么它就不会从内存中清除。

    private var _binding: FragmentMainBinding? = null
    private val binding get() = _binding!!
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentMainBinding.inflate(inflater, container, false)
        return binding.root
    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    ![](/static/blog/img/csdnimg/newCodeMoreWhite.png)
    

    然后就可以像我们在Activity中那样使用它。

    binding.name.text = "Some Text"
    

    View Binding将为模块中的每个XML布局生成一个绑定对象。

    例如这个activity_main.xml布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        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"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    ![](/static/blog/img/csdnimg/newCodeMoreWhite.png)
    

    View Binding将生成ActivityMainBinding.java

    public final class ActivityMainBinding implements ViewBinding {
      @NonNull
      private final ConstraintLayout rootView;
      @NonNull
      public final TextView textView;
    

    View Binding将为每个具有id的视图生成一个正确类型的属性。它还会生成一个名为rootView的属性。
    视图绑定对Kotlin是友好的,因为所有的属性都被注解为@Nullable@NonNull,Kotlin知道如何将它们暴露为空安全类型。

    @NonNull
    public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater) {
      return inflate(inflater, null, false);
    @NonNull
    public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater,
        @Nullable ViewGroup parent, boolean attachToParent) {
      View root = inflater.inflate(R.layout.activity_main, parent, false);
      if (attachToParent) {
        parent.addView(root);
      return bind(root);
    

    ActivityMainBinding.java中,视图绑定会生成一个公共的inflate方法。

    它调用bind,在那里它将获取布局并绑定属性,并进行一些错误检查。

    @NonNull
    public static ActivityMainBinding bind(@NonNull View rootView) {
      // The body of this method is generated in a way you would not otherwise write.
      // This is done to optimize the compiled bytecode for size and performance.
      int id;
      missingId: {
        id = R.id.textView;
        TextView textView = rootView.findViewById(id);
        if (textView == null) {
          break missingId;
        return new ActivityMainBinding((ConstraintLayout) rootView, textView);
      String missingId = rootView.getResources().getResourceName(id);
      throw new NullPointerException("Missing required view with ID: ".concat(missingId));
    ![](/static/blog/img/csdnimg/newCodeMoreWhite.png)
    

    bind方法中,生成的绑定对象将为每个要绑定的View调用findViewById

    那么Kotlin Android Extensions的Parcelize特性呢?

    不要忘了,Kotlin中的Parcelize功能是kotlin-android- extensions编译器插件的一部分,所以如果你的Parcelable类依赖于Parcelize注解,那么移除该插件将使它们无法编译。

    JetBrains将Kotlin Android Extensions中的Parcelize提取到一个新的插件kotlin-parcelize中。

    首先你需要在你的模块中添加kotlin-parcelize插件。

    plugins {
        id 'kotlin-parcelize'
    

    然后更改旧的import语句,将:

    import kotlinx.android.parcel.Parcelize
    
    import kotlinx.parcelize.Parcelize
    
    import kotlinx.parcelize.Parcelize
    import android.os.Parcelable
    @Parcelize
    class User(val name: String, val age: Int): Parcelable
    

    你可能会发现这个IDE错误

    Class ‘User’ is not abstract and does not implement abstract member public abstract fun describeContents(): Int defined in android.os.Parcelable

    别担心,你的应用会很好地构建,这是一个误报的错误,已经在youtrack上被报告,并被修复,所以应该在下一个版本中发布。

    请注意,这个插件只能1.4.20-M2版本开始使用,这个版本也是废弃kotlin-android-extensions编译器插件的版本。

    如果你想尝试一下,你需要在IntelliJ IDEA或Android Studio安装Kotlin EAP 插件 。

  • 选择 ToolsKotlinConfigure Kotlin Plugin Updates
  • Update channel 列表中,选择 Early Access Preview 1.4.x 频道
  • 点击 Check again.
  • 然后点击 Install
  • 这是从kotlin-android-extensions插件迁移到ViewBindingkotlin-parcelize插件时应该做的事情:

  • kotlin-android-extensions插件从build.gradle文件中删除。
  • 从你的Activity和Fragment中删除所有kotlin合成导入语句。
  • 在模块build.gradle文件中启用view Binding功能。
  • 在Activity和Fragment中添加绑定对象,并使用它来设置内容视图和从xml文件访问view。
  • 如果使用Parcelize注释,则将新kotlin- parcelize插件添加到模块build.gradle文件中,并如上所述更改导入语句。
  • 译者瞎叨叨 :其实早在今年3月底,JakeWharton大神就宣布了butterknife的弃用,也是推荐使用View Binding

    看来绑定Android视图的方式不多了,长远看来使用官方的View BindingData Binding是比较稳妥的选择。

    随着jetpack的不断完善,最近一年也看到了许多类似的变化,一些传统方式被废弃。例如Fragment的setUserVisibleHintonActivityCreated,Activity的onAciivityResult等。

    jetpack中加入的新成员DataStoreHiltApp Startup等。可以看出谷歌想为开发者解决开发上的痛点,规范开发规范,加快 Android 应用开发速度。

    长远看来不得不说使用jetpack还是比较放心的,不会担心无人维护。这里也吐槽一个现象,国内存在着大量的优秀开源项目,可是大多都是收割一波star,过个一两年就无人维护了,积攒着越来越多的问题,坑了不少小白。这里不乏一些上千star的热门项目。(其实不维护也没什么,至少说明一下不维护也行)

    反观我们常用的okhttp rxjava glide butterknife等项目,可以说是历史悠久,但还是在不断的开发维护中,让人用着放心。

    叨叨几句行了,大家都不容易,理解万岁~~

  • YouTrack | Deprecate Kotlin Android Extensions compiler plugin
  • YouTrack | Move the Parcelize functionality out of the Android Extensions plugin
  • JetBrains/kotlin |Parcelize: Add integration test for the new kotlin- parcelize plugin
  • Developer Advocate for Android at Google comment on a reddit thread
  • [Android Developers | Use view binding to replace findViewById](https://medium.com/androiddevelopers/use-view-binding-to- replace-findviewbyid-c83942471fc)
  • 本站资源由第三方用户自行上传分享,非本站自制,仅供交流学习之用!获取后请于24小时内删除!版权归原作者享有,如有版权问题,请联系,本站将应您的要求删除!本站不涉及发行、推广及代理! 隐私协议 & © 2021 . All rights reserved