【小鹅事务所】仿照NIA最佳实践重构一个项目后,我沉默了

前言

我一直把我的毕设项目【小鹅事务所】当成日常记账本来使用。

371680979234_.pic_yrKcdpNxef.jpg

可是最近总觉得厌烦了,它的功能都符合我的需求,总觉得差点什么。打开代码一看,金玉在外,败絮其中。看看别人家的NowInAndroid,是如此的优雅。

表面上我还在用着。但是内心已经暗下决心,要把小鹅事务所重构成NIA的样子,它才是我心目中的Android最佳实践。

项目架构重构

首先要着手重构的当然是项目架构。小鹅事务所的架构是这样的:

image_QmXIP2o7AL.png

包含3个模块,CalendarView日历模块来源于开源项目。实际上其实所有应用代码都写在了app模块中,也就是一个单模块的项目,app模块中又包含了记事本、记账本、事务、纪念日的代码耦合在一起。

它的好处就是写起来很爽。但是这不行啊,你看看别人NIA分为十几个模块井井有条,有鼻子有眼的。我这个就全部挤在一团,丑死了。于是我打算把不同的模块先抽出来弄成这个样子。

image_6_T-Ep4lfR.png

刚开始动工,我又犯难了,项目依赖SDK的时候全部写在dependencies里的。如果要挪成不同的模块,第一个需要解决的就是依赖版本的统一。

image_-GzejeO2zL.png

VersionCatalogs

在NIA项目中有一个libs.version.toml文件管理依赖,它的官方文档是这个docs.gradle.org/current/use…

If a libs.versions.toml file is found in the gradle subdirectory of the root build, then a catalog will be automatically declared with the contents of this file.

也就是说只要新建一个libs.version.toml文件到gradle文件夹中,就会自动生成一个VersionCatalogs,可以直接在依赖的时候拿来用。

这种方式太优雅了,这小代码写的可真够俏。

image_bNTQRO5pM7.png

image_I8JgDvNRl5.png

为什么在plugins无法识别出现爆红呢?于是我看了一下NIA,也有这个问题,他们是加了一个注解@Suppress("DSL_SCOPE_VIOLATION")解决的,并且注释了一个链接,有兴趣可以看看。youtrack.jetbrains.com/issue/KTIJ-…

image_WvHiy3JVwv.png

Plugins

上面截图中出现的id(xxx.android.library)其实就是使用了Gradle的注册Plugin的功能,只需要在build-logic中的build.gradle注册就可以了,就可以在编译的时候自动运行执行Plugin类的逻辑,而这个Plugin类可以自定义。

gradlePlugin {
    plugins {
        register("androidApplicationCompose") {
            id = "nowinandroid.android.application.compose"
            implementationClass = "AndroidApplicationComposeConventionPlugin"
        }
        ...
    }
}

复制代码
class AndroidApplicationComposeConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            pluginManager.apply("com.android.application")
            val extension = extensions.getByType<ApplicationExtension>()
            configureAndroidCompose(extension)
        }
    }
}
复制代码

在Kotlin类中写Gradle编译代码,还有代码联想,这多是一件美事啊,编译代码还可以互相复用,例如下面的configureAndroidCommon函数。

image_mhI10BQyFI.png

build-logic复合构建

上文中经常出现build-logic,它的作用其实和buildSrc类似,用来定义编译脚本的。上文的Plugin就可以写在这个项目中。

buildSrc不同,它是一个独立的Gradle项目,不依赖当前项目,也就是说可以独立编译。于是它就享受不到自动生成的VersionCatalogs了,怎么办呢?

官方文档写得很明确,可以在另一个项目的settings.gradle.kts中找到指定文件显式去生成。

versionCatalogs {
    create("libs") {
        from(files("../gradle/libs.versions.toml"))
    }
}
复制代码

关于build-logic的减少重复构建、减少构建时间的之类好处就不细说啦。

分模块

到这里终于可以将app模块的代码抽出来分成多个模块了,由于我写了很多Plugin插件,所以在新建模块的时候就可以很好的复用了,举个例子我想弄一个home模块,build.gradle.kts可以写成这样。

image_tq17tfCGk0.png

剩下的就只有挪代码、挪代码和处理爆红代码的工作了,非常枯燥。

就像整理一个杂乱无章乱七八糟的房间那样。一开始会干劲十足,等做到后面会慢慢开始泄气。我怎么写了这么多东西,这些代码为什么耦合度会这么大,此时我还没意识到,这仅仅只是一个开始。

View替换成Compose

我刚做这个毕设项目的时候,Compose刚出1.0稳定版。

我说:我要用全Compose来写UI界面,是不很大胆

我将这个全Compose计划告诉我的其他同学,他们都很兴奋。

我说:只用三周,一周学习,一周编写代码,一周改BUG就可以写完这个项目。

国内很少资料,我参考了很多国外的资料,Compose实在太酷了。

image.png

经过一年多对Compose的研究和实践,我发现我还是忘不了这个计划,我很想把小鹅事务所变成Compose的模样。

设计

既然当初用的Material2来设计小鹅事务所,那现在,我就要用Material3设计,还要加入Android12最新的动态配色!

于是我打开了Figma,刚想来一场酣畅淋漓的设计。后来我想想,设计稿的用处是设计用来和开发对接的产物。而我既是设计也是开发,设计稿就变成了一个可有可无的东西。

image_7mo_kFolwT.png

Compose代码编写

刚开始将View换成Compose的时候,我非常兴奋,终于可以大规模地实践Compose了。我于是把代码写得非常规范,甚至在控件中加上Preview。每每写完一个控件,就美美把之前的View和Layout文件删除。

当这项工作进行到一半的时候,我发现之前的UI界面好多,有的写得非常优雅,有的写得有点乱。每一行代码都牵引出我的回忆,有种帮同居对象搬走这个屋子的感觉。

慢慢地删除旧代码带来的剥离感让我陷入了沉思,我是不是一开始就不应该开始这项重构工作,凑合凑合也不是不能用。但是Compose带来的新鲜感让我无法拒绝。

在不断自我拉扯中,我潦草地完成了这些工作,Preview也不写了,代码也不那么优雅了。

在重构完成之际,我决定留下了这几行代码作为纪念。

image_fOpddxnmgH.png

思考

小鹅事务所的重构一期工作暂且告一段落,花了3个多月,仍然没有重构到NIA那般样子

我在工作中也不断接触Android项目,有的项目在使用Java,很多项目仍然使用过去的架构、架构、设计模式。当Android最佳实践不断推陈出新的时候,不是所有项目都能跟得上。我这么一个小项目稍微重构一下都需要花上几个月时间,而大项目是几乎不可能像这样大规模重构的,这得花多少时间啊...这就造成了一个成规模的项目无法真正追赶上谷歌所谓的“最佳实践”。

Android的最佳实践只是一种理想,在历史代码和程序员考核面前,它似乎一文不值。

代码

最后放一下重构之后的代码仓库: github.com/MReP1/Littl…

猜你喜欢

转载自juejin.im/post/7219862257644961849
今日推荐