You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
41 lines
4.4 KiB
41 lines
4.4 KiB
---
|
|
项目总结相关口水话
|
|
---
|
|
|
|
#### 目录
|
|
|
|
1. 组件化 + MVP
|
|
2. 项目中遇到哪些问题,是怎么解决的?
|
|
|
|
#### 项目架构
|
|
|
|
我们项目采用的是组件化 + MVP。
|
|
|
|
模块化大家都知道,new 一个 App Module 即可,组件化不过是模块化更细粒度的表现。我们项目的大致架构是:
|
|
|
|
/** 此处该有张图 **/
|
|
|
|
组件化需要解决两个问题,业务模块的划分以及组件间的通信。业务模块的划分是比较麻烦的,因为之前写的都耦合在了一起,目前我们也只有一个发票的模块独立拆分了出来。组件间的通信可以采用 ARouter。ARouter 的源码我倒是没有看过,不过之前也写过路由跳转,核心的思想就是生成一个 Map,Path 对 Activity 的映射。实现方式有两种,第一种是通过元数据的形式,即在 Manifest 注册 Activity 时添加 meta-data 信息,然后在 Application 的 onCreate 时去扫描所有的 Activity 生成 Map,这种方式实现简单,几十行代码就能写完了。第二种方式则是比较传统的通过编译时注解 + JavaPoet 的形式,和 ButterKnife 原理一样。但是写的时候还是发现一些问题的,注解处理器在每个模块下都要引入,生成的类的全限定名是当前的包名 + 类名,里面就一个 public static 的方法,方法里面就是写好的 HashMap 一系列的 put 方法,接下来就是要每个模块生成的 Map 进行合成即可,但是问题来了,在 app 模块是不知道其他模块的名字呀,于是只能在 assets 目录下配一个 json 文件用来读取每个模块的模块名,有了模块名就有了前面生成的类的全限定名了,然后反射执行方法合成 Map 即可。
|
|
|
|
接下来就说说 MVP,MVP 相对于 MVC 来说,完全解耦了 View 层和 Model 层。主流的实现方式是以 Activity 作为 View 层,Presenter 层负责网络请求和数据处理,然后把处理后的数据以接口回调的方式传给 View 显示。
|
|
|
|
然后,就没了
|
|
|
|
#### 遇到哪些问题,是如何解决的?
|
|
|
|
##### 输出项目里的权限信息
|
|
|
|
这个在 Gradle Plugin 口水话里面讲过,就不多说了。
|
|
|
|
##### getGlobalVisibleRect
|
|
|
|
有一个需求是需要判断一个 TextView 在屏幕内是否可见,然后我就网上搜了一下,发现有一个 getGlobalVisibleRect 这个 Api,它返回的是一个 boolean 值,看了一下文档,可以传一个 Rect 作为参数,之后会拿可见区域的信息给这个 Rect 赋值。起初我是用这个返回值直接判断的,但是后面测试反馈说有 bug,我这测试也没啥问题呀。琢磨了半天才发现,原来顶层布局是一个 ScrollView,ScrollView 会把所有的子 View 一下子全都加载进来,所以这个 getGlobalVisibleRect 会一直返回 true。解决办法就是拿 Rect 的 top 去和屏幕的高判断,如果大于屏幕的高,就说明不在屏幕内,然后测试反馈说有一个小屏手机还是有问题。我去一看,稍微滑动一点,TextView 就显示出来了,我打印了 Rect 的信息,发现真的巧合,它的高度刚好比屏幕的高度高 1 个像素,但是由于 TextView 本身有上边距的影响,导致实际上不可见,然后判断的时候加个 10 像素就行了。
|
|
|
|
##### 构建优化
|
|
|
|
测试有一次反馈打包好慢呀,我试了一下,我们打 debug 包耗时半分钟左右,但是测试在 Jenkins 打 debug 包却接近了两分钟。没得办法,搞一下,之前也参加过 DroidCon 和携程、有赞的关于编译优化的技术分享,拿出来实践一下。最后呢,成果是全量编译由之前的 1m 59s 到 1m 1s,代码增量编译由之前的 27s 到 9s,资源增量由之前的 8s 到 10s。除了资源的逆优化,其他优化效果都非常明显。
|
|
|
|
Gradle 的执行分为三大阶段:Initialization -> Configuration -> Execution 阶段。Initialization 阶段主要目的是初始化构建,它分为两个子过程,一个执行 Init Script,另一个执行 Setting Script。Init Script 会读取全局脚本初始化一些通用的属性,比如 Gradle User Home 目录、Gradle version 等。Setting Script 更常见,它初始化一次构建所参与的所有模块。Configuration 阶段主要影响全量构建的时间,而 Execution 阶段则主要影响增量构建的时间。
|
|
|
|
具体优化措施我在 Gradle 口水话中已经说了,我就不多哔哔了。
|
|
|
|
|