ViewBingding?搞!

简介: kotlin-android-extensions插件

为啥搞

其实之前也看到了 AndroidStudio 给出的提示,说 kotlin-android-extensions 已经被废弃,当时也没当回事,前两天有点问题需要写一个 Demo 的时候就新建了一个项目,按照往常一样直接在 Activity 中使用控件的 id 进行调用,但是发现报错,新建的项目中已经默认不集成 kotlin-android-extensions 了,好坑啊!

要说之前为什么开始使用 Koltin ,不用再写 findViewById 绝对是一大原因,但是现在竟然直接给我废弃了!好坑。

无独有偶,刚发现这个问题没两天 「郭霖」 就发了一篇文章:

kotlin-android-extensions插件也被废弃了?扶我起来

里面详细讲了 ViewBinding 的使用方法,于是就想在我的 「玩安卓」 使用下,但使用期间出了一些小问题,且听我娓娓道来🐶

再放下项目的Github地址:github.com/zhujiang521…

注:本文不写 ViewBinding 的基本用法, 郭神写的基本用法比我好的多,大家可以移步上面的链接。

开始搞

要搞就搞得彻底点,在主 module 中直接把 kotlin-android-extensions 依赖给移除了:

plugins {
    id 'com.android.library'
    id 'kotlin-android'
    id 'kotlin-android-extensions'
}

直接把上面代码中最下面一行删除就可以了,然后再添加上 ViewBinding 的依赖:

android {
  ……
    buildFeatures {
        viewBinding true
    }
}

这些都挺简单,但具体是哪块出现问题了呢?这个问题其实说起来也算是我自己之前挖的坑,项目的首页,之前为了适配横竖屏布局,自定义了两个不同的控件,在布局中也是横竖屏各自放着各自那个布局,

<?xml version="1.0" encoding="utf-8"?>
<com.zj.play.main.HomeBottomLandTabWidget xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/homeLandView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
<?xml version="1.0" encoding="utf-8"?>
<com.zj.play.main.HomeBottomTabWidget xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/homeView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

很简单,在使用的时候直接判断当前屏幕的状态来选择加载的布局即可。

override fun initView() {
    isPort = resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
    when (isPort) {
        true -> homeView.init(supportFragmentManager, viewModel)
        false -> homeLandView.init(supportFragmentManager, viewModel)
    }
}

原本不使用 ViewBinding 的时候是没问题的,可以正常运行,但是!当使用了 ViewBinding 之后,运行直接报错了:

Configurations for activity_main.xml must agree on the root element's ID.
@+id/homeLandView:
 - layout-land
@+id/homeView:
 - layout

错误信息很明显,因为两个布局的根元素的 id 必须一致!既然这样,那就在布局外面都套一层布局吧:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.zj.play.main.HomeBottomTabWidget
        android:id="@+id/homeView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.zj.play.main.HomeBottomLandTabWidget
        android:id="@+id/homeLandView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

改了之后,成功运行。

第二个问题是在自定义控件中使用 ViewBinding,郭神在文章中写了在 Activity、Fragment 以及 Adapter 中使用,但没有写怎样在自定义 View 中使用,其实写不写都行,因为很简单。。

private fun initView() {
    //加载布局
    val binding = LayoutToTopBinding.inflate(LayoutInflater.from(context), this, true)
}

对,这就可以了,和在 Fragment 中使用基本一致,需要传递三个参数,第一个是 inflater,有 context 可以直接创建出来,第二个是 ViewGroup,在自定义 View 中也容易拿到,第三个参数是 是否绑定到根元素,根据需求写即可,如果写成 false 的话,下面也可以通过 addView 的方式将 View 添加到布局上。

如果需要全局使用的话直接定义成全局的变量,在不用时注意置空即可。

第三个问题时郭神在文章中所说的 ViewBinding 在 Adapter 中的写法,评论中有一个大哥提出了不同的看法:

 class FruitAdapter ( val fuitList : List < Fruit >): RecyclerView . Adapter < FruitAdapter . ViewHolder >()
 inner class ViewHolder ( binding : FruitItemBinding ): RecyclerView . ViewHolder ( binding . root )( val fruitImage : ImageView = binding . fruitImage 
 val fruitName : TextView = binding . fruitName
 }
 override fun oncreateviewHolder ( parent : ViewGroup , viewType : Int ): viewHolder (
 Va D1nding FruitItemBinding . inflate ( LayoutInflater . from ( parent . context ), parent , false )
 return ViewHolder ( binding )
 }
 override fun onBindViewHolder ( holder : ViewHolder , position : Int ){
 val fruit = fruitList [ position ]
 holder . fruitImage . setImageResource ( fruit . imageId )
 holder . fruitName . text =fruit.name
 }
 override fun getItemcount ()= fruitList , size 
 }

74753fc53f01aeaed09e529538405e93.png

想了想也确实是,本来使用 ViewBinding 就是为了不写 findViewById 的,结果像上面那样写的话反而麻烦了一些,还不如直接 findViewById 来的快,还不用引入 ViewBinding。

下面先来创建一个 Adapter 的基类吧:

abstract class BaseRecyclerAdapter<V : ViewBinding> :
    RecyclerView.Adapter<BaseRecyclerAdapter.BaseRecyclerHolder<V>>() {
    abstract override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseRecyclerHolder<V>
    override fun onBindViewHolder(holder: BaseRecyclerHolder<V>, position: Int) {
        onBaseBindViewHolder(position, holder.binding)
    }
    abstract fun onBaseBindViewHolder(position: Int, binding: V)
    open class BaseRecyclerHolder<V : ViewBinding>(val binding: V) :
        RecyclerView.ViewHolder(binding.root)
}

基类代码很简单不做过多介绍,接下来看下改造后的代码吧:

class FruitAdapter(val fruitList: List<Fruit>) : BaseRecyclerAdapter<FruitItemBinding>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseRecyclerHolder<FruitItemBinding> {
        val binding = FruitItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return BaseRecyclerHolder(binding)
    }
    override fun onBaseBindViewHolder(holder: BaseRecyclerHolder<FruitItemBinding>, position: Int) {
        val fruit = fruitList[position]
        binding.apply{
            fruitImage.setImageResource(fruit.imageId)
            fruitName.text = fruit.name
        }
    }
    override fun getItemCount() = fruitList.size
}

其实也没有少写多少代码,但个人总感觉清爽了些许。

搞结束

其它的按照郭神写的已经足够使用了,修改也挺简单,我的「玩安卓」一共用了几个小时就将整个项目全部换成了 ViewBinding。

希望 Google 不要太早对 ViewBinding 下手,也说不准,毕竟还有 compose 在一旁虎视眈眈地观望着呢。。。



目录
相关文章
|
6月前
aviator 属实搞事情
aviator 属实搞事情
52 0
|
网络协议 Linux
又被鹅厂搞懵了!
客户端(主动关闭方)在 TIME_WAIT 状态下,如果收到服务端的数据包时,会怎么处理?
又被鹅厂搞懵了!
|
Web App开发 搜索推荐 开发者
上了学这么久,我才知道他们为什么可以这么爽(上)
目录 前情提要 安装插件 1.下载链接 2.安装 遇到无法拖进去怎么办? 3.新的体验
上了学这么久,我才知道他们为什么可以这么爽(上)
您了解对方吗?不了解的话那就只能算是“剃头挑子一头热”了,呵呵。
     博客园就像一个大家庭,大家来自五湖四海,互相帮助,共同提高,本来是挺好的。但是如果有“与众不同”的出现的话,就很容易引起轩然大波,有关心的、有反对的、有赞成的。也有忍不住在首页跟贴的。呵呵。
631 0
|
程序员
程序员好心帮应届生改代码后,结果扎心了!
近日,一名程序员在互联网社区的吐槽:公司一个应届毕业生,领导安排和我一起做项目,提交的代码有许多不合适的地方,我在没有和他提前沟通的情况下做了部分重构,结果直接喷我,让我不要改他的代码,老哥们,遇到过这种情况吗?对此,网友是如此评论的: 直接说让他自己改,改之前你应该先说,不过应届生也敢喷你,不是后台强,就是情商低;千万别自己改,你应该给他说怎么改,然他自己改,我就是应届生,我领导就这样做的。
1008 0
|
机器学习/深度学习 人工智能 大数据
对于搞技术的人怎样针对自己看什么书
  今天有同事问我需要看什么书,其实我有点很难回答这个问题,其实之前我的同学圈也讨论过这个问题,其实我感觉这些人其实可能是最近比较迷茫了,   不知道人生的下一步该怎么走。然后我的回答就是,每个人的人生都是有差异的,都是不同的不能用别人的成功经验在套在自己的身上,   但是我们可以从他们的经验来学习,吸取适合自己的为自己所用。
1162 0

相关实验场景

更多