欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

谁才是ButterKnife的终结者?ViewBinding与Kotlin-android-extension的选择

程序员文章站 2022-06-07 18:49:33
...

谁才是ButterKnife的终结者?ViewBinding与Kotlin-android-extension的选择
Google在Android Studio 3.6 Canary 11版本中正式推出视图绑定(View Binding),相对有findViewById或者Butter Knife等现有的视图访问方式更有优势,JakeWharton也因此宣布了Butter Knife的终结。
谁才是ButterKnife的终结者?ViewBinding与Kotlin-android-extension的选择

Kotlin-android-extension


使用Kotlin的同学都知道Kotlin-android-extension可以方便的进行视图访问,所以Kotlin开发中很少使用Butter knife。ViewBinding难道比KAE还强大吗,ViewBinding与KAE谁才能扛起Butter Knife后时代的大旗呢?

要找到答案就要比较一下两者的优劣,曾几何时看过一张表格,似乎ViewBinding比KAE更有优势:(Kotlin Synthetic:KAE, ???:ViewBinding)
谁才是ButterKnife的终结者?ViewBinding与Kotlin-android-extension的选择

KAE是基于Kotlin Compiler Plugin + Intellij Idea Plugin实现的,IDEA Plugin让我们可以在编辑器中使用语法糖进行试图访问,Compiler Plugin可以在编译期对语法糖脱糖。整个过程是一个编译期的的闭环,何来的编译安全问题呢?

我们知道KAE可以将layout文件中的id映射为View对象直接在Activity或Fragment中使用,但是无法保证layout是Activity/Fragment的当前视图

例如有两个layout :activity_mainactivity_other

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

    <TextView
        android:id="@+id/message_main"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                >

    <TextView
        android:id="@+id/message_other"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</RelativeLayout>

我们实现Activity如下:

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_other.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //Application will crash because "message_other" doesn't exist in "activity_main"
        message_other.text = "Hello!"
    }
}

KAE会扫描res下所有layout中的id,作为代码自动补全的候选项,message_other的使用虽然可以通过编译,但是因为不是当前layout中的id,所以运行时会出错。

同样的例子如果使用ViewBinding则可以避免上述问题

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        //This code will never compile and the IDE shows you an error
        binding.message_other.text = "Hello!"
    }
}

上面表格中KAE编译安全的✘也正是指的这个问题。

Null safety


还有另一张表格也做了两者的对比,当然也是以突出ViewBinding为前提
谁才是ButterKnife的终结者?ViewBinding与Kotlin-android-extension的选择
Only reference ids from current layout 在上面的例子已经介绍过了。Alway null-safe该如何理解呢?

先看下ViewBinding的Null-safe

Null-safe for layouts defined in multiple configurations. View binding will detect if a view is only present in some configurations and create a @Nullable property.

当有多个configuration时,需要对应多个layout,此时可能出现为空的情况,ViewBinding会在编译期发现并添加@Nullable注解。

经过实测,KAE也可以做到这一点,当某个configuration的layout缺少时,KAE同样会给出提示:
谁才是ButterKnife的终结者?ViewBinding与Kotlin-android-extension的选择
需要进行可空处理:
谁才是ButterKnife的终结者?ViewBinding与Kotlin-android-extension的选择

所以在空安全方面,ViewBinding并不比KAE有优势

How to choose?


啰嗦了这么多,到底应该如何选择呢?

首先客观的说ViewBinding比KAE的优势并不明显,都兼具了类型安全、空安全
编译速度等方面的优势(编译速度可能KAE更加,KotlinCompilerPlugin由于GradlePlugin),虽然KAE在编译安全上有缺陷,但只要开发时稍加注意也不是大问题,而且KAE的模板代码比起ViewBinding更少,从简洁性上说要更优秀,所以个人认为在Kotlin开发中,KAE与ViewBinding是不分伯仲的。

但是ViewBinding有一个优势KAE无法比拟,就是身份问题:

KAE来自JetBrains而非Google官方的,随着ViewBinding的诞生,相信Google会在未来的AOSP以及Jetpack中更多地推荐使用ViewBinding,例如下面某个commit的comment中已经可以看出端倪

kotlinx.android.synthetic is no longer a recommended practice
https://android-review.googlesource.com/c/platform/frameworks/support/+/882241

虽然JetBrains对于KAE来说已经是一种背书了,但是在Android世界中毕竟Google才是老大(参考Anko与Jetpack-KTX的现状),所以你心中的是否已经有答案了呢?