1、组件化在项目中的意义
如果没有组件化,会发生什么?
- 无层次:无论怎么分包,项目越做越大时,项目会没有层次。
- 不同业务包相互调用:包名约束太弱,稍有不注意,巨响不同业务包直接相互调用,代码高耦合
- 多人在开发版本管理中,容易出现代码覆盖冲突等问题
组件化的意义
- 不相互依赖
- 可以相互交互
- 任意组合,高度解耦,自由拆卸,自由组装,重复利用,分层独立化
组件化目的是复用,模块化是业务分隔
App是壳子,业务model平起平坐,基础组件坐一排。
组件与组件的通信方式哪些?
- 方法一:EventBus,但是不好维护
- 方法二:广播,不好管理
- 方法三:隐式意图,清单文件里写太多
- 方法四:类加载,包名容易写错
- 方法五:全局Map的方式,缺点要注册很多的对象。
- 方法六:使用阿里巴巴开源框架ARouter
2、组件化的ARouter原理
步骤
- 注册子模块信息到路由表里,用APT,编译时,扫描自定义注解,通过注解获取子模块信息,并注册到路由表里面去
- 寻址操作,寻找到在编译器注册进来 的子模块,完成交互即可。
3、谈谈你对APT技术的理解
- APT全称,注解处理器,Annotation Process Tool。主要用于再代码编译时扫描和处理注解。常被用于减少重复代码的手工编写,就是编译时额外生成Java文件,
- 像bufferknife、EventBus、DataBinding,JetPackRoom都是用的APT技术来生成代码
- 就是一行一行地拼接包类函数等方式。可读性还是不错的。像ARouter框架,就是采用JavaPoet生成代码的,用的面向对象的思想来生成,不需要一行一行的拼接,更符合开发者思维。
4、谈谈Glide框架的缓存机制的设计
目的
- 减少流量消耗,加快响应速度
- Bitmap的创建/销毁比较耗内存,可能会导致频繁GC,使用缓存可以更加高效地加载Bitmap,减少卡顿
Glide缓存流程
- 存是 弱引用-》LruCache-》磁盘,取是 反过来,存取的入口再Engine这个类
- 其实就是活动缓存,内存缓存,磁盘缓存
弱引用
是一个HashMap维护,key是缓存的key,由0url、width、height等10个参数组成,value是对图片资源对象的弱引用。
LruCache
是一个由LinkedHashMap维护,根据Lru算法来管理图片,大致原理是利用linkHashmap链表特性,把最近使用过的文件插入到列表头部,没有使用的土拍你放在尾部,当图片大小达到预设的阈值的时候u,按算法删除列表尾部的部分数据。
硬盘缓存原理
- Glide硬盘缓存策略
- DiskCacheStrategy.DATA: 只缓存原始图片;
- DiskCacheStrategy.RESOURCE:只缓存转换过后的图片;
- DiskCacheStrategy.ALL:既缓存原始图片,也缓存转换过后的图片;对于远程图片,缓存 DATA和
- RESOURCE;对于本地图片,只缓存 RESOURCE;
- DiskCacheStrategy.NONE:不缓存任何内容;
- DiskCacheStrategy.AUTOMATIC:默认策略,尝试对本地和远程图片使用最佳的策略。当下载网络图片时,使用DATA(原因很简单,对本地图片的处理可比网络要容易得多);对于本地图片,使用RESOURCE。
- 没有缓存咋办?
- 通过EngineJob开启线程池去加载图片,有两个关键类,EngineJob和DecodeJob。前者维护了线程池,用来管理资源假爱,资源加载完毕的时候通知回调。
- DecodeJob是线程池中的一个任务。磁盘缓存时通过DiskLurCache来管理的,根据缓存策略,会有2钟类型的图片,DATA(原始图片)和RESOURCE(转换后的图片)。磁盘依次通过ResourcesCacheGenerator(转换过的缓存数据,主要是bitmap,在内存上)、SourceGenerator(未经转换的原始缓存数据)、DataCacheGenerator(是通过网络获取图片再按照缓存策略的不同去缓存不同的图片到磁盘上)来获取缓存数据。
总结
- Glide缓存分为 读取顺序 弱引用+LruCache+DiskLruCache。
- 弱引用的是正在使用可见的图片,也就是活动缓存
- 内存缓存,Lurcache,当暂时使用不到的图片都放在这里,通过图片引用计数器来实现的
- 磁盘缓存,就是查过了内存缓存数量,其它就放到这里。有存原图,有存转换过后的。如果实在没有就去网络,然后存到磁盘再弱引用。
5、谈谈你对Glide生命周期的理解
- Glide通过RequestManagerFragment,内部 构建五UI的Fragment完成生命周期监听。它在RequestManagerRetriever类的getREquestManagerFragment被调用。
- 就是一个目的,得到Fragment并且返回这个Fragment。先通过findFragmentByTag获取,如果为null,则会pendingRequestManagerFragments这个Map集合去获取,如果还是为null,则直接new 一个Fragment,并且保存到pendingRequestManagerFragments以及添加到Activity中。这部分的代码就是Fragment和Actvity关联上了,这样就可以通过Fragment得知当前Activty的生命周期。追踪RequestManagerFragment,看看它的生命周期里面做了什么操作,源码如下。
- Fragment的的生命周期里(我们只关注贴出代码的三个生命周期),ActivityFragmentLifecycle类都调用了相同名字的方法,接下来看看ActivityFragmentLifecycle的相应方法里面有什么操作。其实就是通过fragment来搞生命周期,里面都有LifecycleListener
6、项目使用Glide框架出现内存移除,应该是什么原因》?
- 应该是作用域问题,传入的时候尽量传入非Application作用域,因为Application作用域不会对页面绑定生命周期机制,就不会即使释放
顺便讲一下Glide中的作用域?
- 作用域Application,生命周期是全局的,不搞空白Fragment来覆盖监听Activity/Frament
- 作用域非Application,专门搞个空白Fragment来覆盖监听Activity/Frament
7、谈谈Okhttp框架原理
- OKhttp是当前Android使用最频繁的网络请求框架,Android 4.4之后HttpUrlConnection底层实现也成了OKHttp。目前流行的REtrofit底层的网络请求也是用的OkHttp
- 优点
- 支持Http1、Http2、Quic以及WebSocket
- 连接池复用底层TCP(Socket)
- 无缝的支持GZIP减少数据流量
- 缓存响应数据减少复用的网络请求
- 请求失败自动重试主机其它的IP,自动重定向 详细介绍看 我这篇文OkHttp源码流程简述 - 掘金 (juejin.cn)
8、Android如何发起网络请求,你有用过相关框架吗?OkHttp框架解决了你什么问题?
- 现在绝大多数网络交互采用Http协议,当然也有webSocket ftp 等
- 首先 应用层、表示层、会话层 、传输层、 网络层、 链路层物理层、
- TCP就是传输层协议 IP就是网络层协议
- 写网络程序就必须用Socket,它就是对TCP/IP协议的封装,也就是说Http需要先利用Socket建立TCP/IP连接,然后就可以使用SOcket读写数据,这个数据需要按照Http协议的规则、语意去封装与解析,这样就完成Http通信了。如果是按照WebSocket的规则定制数据,就是在完成WebSocket的通信
OkHttp解决了你什么问题?
- 连接池
- GZip压缩
- 响应缓存
- Cookie DNS服务器 代理
- 另外接口友好,功能齐全。
- 因为每个人有自己的编码风格,单单一个网络访问,每个人都有不同的写法和封装。在一个项目中,这种代码必然是冗余的。而使用公开的框架,能够把大家的能力尽可能拉平到一条线上,避免一些基础错误。
OkHttp的缺点
- 当然有些同学可能说没有封装线程切换,嵌套请求不方便啥的,数据解析啥的。但在我看来这个不是OkHttp的缺点。他很完美。
- OkHttp是一个Java框架,并不是专用于Android。它的定位就是网络基础功能库,不需要考虑我们业务需要去浅谈调用,切换线程等。要么我们可以自己封装,要么可以用REtrofit来封装。
9、RXJava框架线程切换的原理,RxJava1与RxJava2有哪些区别?
线程切换原理
- 切换时用的Scheduler调度器
observable.subscribeOn(Schedulers.io()).
observeon(AndroidSchedulers.mainThread()).
subscribe(observer)
- RxJava切换线程分为两部分:subscribeOn()和observeOn()
- subscribeOn()
- 我们传进去了一个Scheduler类,Scheduler是一个调度类,能够延时或周期性地去执行一个任务。
- subscribeOn方法内部会使用一个线程池来执行被观察者的所有操作。这个线程池通常是由Executors类或自定义实现
- 被观察者生成数据并通过Observable发出数据。这些数据会通过Observable的内部机制进行传递,最终到达observeOn指定的线程。
- observeOn()
- 最终返回一个ObservableObserveOn对象而已
RxJava1和RxJava2区别
- RxJava 2.0 不再支持 null 值
Observable.just(null); Single.just(null); Flowable.just(null);
-
RxJava 2.0 所有的函数接口(Function/Action/Consumer)均设计为可抛出Exception,解决编译异常需要转换问 题;
-
RxJava 1.0 中Observable不能很好支持背压,在RxJava2.0 中将Oberservable彻底实现成不支持背压,而新增
Flowable 来支持背压。
10、谈谈LiveData的生命周期是怎么监听的?
- LiveData就是接住了LifeCycle感知生命周期的。讲LifeCycleBoundbserver wrapper添加为观察者,当生命周期变化时将会执行:onStateChanged
- 在activeStateChanged中如果当前改变的状态为活跃状态(shouldBeActive():true),则会调用considerNotify方法通知数据更新:
- 数据在每次修改时,都会进行mVersion++,因此可以使用mVersion判断数据是否发生修改,如果未发生变化则不会发起回调。
- LiveData的生命周期是通过Lifecycle监听的,同时LiveData会维护一个mVersion作为数据的版本号。当数据有修改时,才会进行通知回调。
- 其实主要是一种状体而并非时间。