Android开发经验谈面试题

腾讯被面Okhttp3 惨挂,我总结了一套学习心得

2020-07-16  本文已影响0人  Alvin老师

OKhttp3 是最近比较主流的网络请求框架。面试中,常会问道你对okhttp3是否有深入的了解。在这篇文章我总结了下okhttp3的原理(非用法,用法自己百度就行),以及大神们根据源码分析OKhttp3比较好的文章。

1.首先是大神们对OKhttp3的源码分析:(转载)

Android OkHttp(三)源码解析:https://blog.csdn.net/zxw136511485/article/details/52872724 (这是我第一篇看的okhttp的源码解析,根据这篇文章和自己查看okhtttp 源码,看okhttp内部,这篇文章大概讲清楚okhttp 内部构造,虽然有些语言表达上的错误,这篇也是针对okhttp的.建议可以先看这篇,先了解大概)

okhttp源码解析:https://blog.csdn.net/json_it/article/details/78404010 (这是第二篇,也是最近在看的一篇,大神分析的比较全,也比较准确,详细解析的okhttp3)

OkHttp3源码分析[综述]:https://blog.csdn.net/json_it/article/details/78404010 (这篇是将源码分析,拆成了5个部分,分析也很很好,适合看)

Android okhttp3 创建Socket的底层实现追踪 :https://blog.csdn.net/hello2mao/article/details/53159151 (这篇描述了OKhttp3 socket底层的实现)

OkHttp3源码和设计模式:
https://www.imooc.com/article/24025?block_id=tuijian_wz (这篇从设计模式的角度分析OKhttp3)

OkHttp3对RealCall的注释及上篇是Dispatcher

https://blog.csdn.net/dingding_android/article/details/51942000

2.根据所看的文章,及源码的查看,自己做了简略的总结

Okhttp3: 从以下方面总结

为什么okHttp3 好用呢?

OkHttp是一个精巧的网络请求库,有如下特性:

1)支持http2,对一台机器的所有请求共享同一个socket

2)内置连接池,支持连接复用,减少延迟

3)支持透明的gzip压缩响应体

4)通过缓存避免重复的请求

5)请求失败时自动重试主机的其他ip,自动重定向

6)好用的API

实现网络请求方法:

OkHttp3的最底层是Socket,而不是URLConnection,它通过Platform的Class.forName()反射获得当前Runtime使用的socket库

socket发起网络请求的流程一般是:
(1). 创建socket对象;
(2). 连接到目标网络;

(3). 进行输入输出流操作。

(1)(2)的实现,封装在connection接口中,具体的实现类是RealConnection。
(3)是通过stream接口来实现,根据不同的网络协议,有Http1xStream和Http2xStream两个实现类
由于创建网络连接的时间较久(如果是HTTP的话,需要进行三次握手),而请求经常是频繁的碎片化的,所以为了提高网络连接的效率,OKHttp3实现了网络连接复用

运用到的设计模式:

单例模式:(建议用单例模式创建okHttpClient)OkHttpClient, 可以通过 new OkHttpClient() 或 new OkHttpClient.Builder() 来创建对象, 但是---特别注意, OkHttpClient() 对象最好是共享的, 建议使用单例模式创建。 因为每个 OkHttpClient 对象都管理自己独有的线程池和连接池。 这一点很多同学,甚至在我经历的团队中就有人踩过坑, 每一个请求都创建一个 OkHttpClient 导致内存爆掉

外观模式 : OKHttpClient 里面组合了很多的类对象。其实是将OKHttp的很多功能模块,全部包装进这个类中,让这个类单独提供对外的API,这种设计叫做外观模式(外观模式:隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口)

Builder模式 : OkHttpClient 比较复杂, 太多属性, 而且客户的组合需求多样化, 所以OKhttp使用建造者模式(Build模式:使用多个简单的对象一步一步构建成一个复杂的对象,一个 Builder 类会一步一步构造最终的对象)

工厂方法模式:Call接口提供了内部接口Factory(用于将对象的创建延迟到该工厂类的子类中进行,从而实现动态的
配置,工厂方法模式。(工厂方法模式:这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。)

享元模式:在Dispatcher的线程池中,所用到了享元模式,一个不限容量的线程池 , 线程空闲时存活时间为 60 秒。线程池实现了对象复用,降低线程创建开销,从设计模式上来讲,使用了享元模式。(享元模式:尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象,主要用于减少创建对象的数量,以减少内存占用和提高性能)

责任链模式:很明显,在okhttp中的拦截器模块,执行过程用到。OkHttp3 的拦截器链中, 内置了5个默认的拦截器,分别用于重试、请求对象转换、缓存、链接、网络读写(责任链模式:为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。)

策略模式 :CacheInterceptor 实现了数据的选择策略, 来自网络还是来自本地? 这个场景也是比较契合策略模式场景, CacheInterceptor 需要一个策略提供者提供它一个策略(锦囊), CacheInterceptor 根据这个策略去选择走网络数据还是本地缓存。
缓存的策略过程:
1、 请求头包含 "If-Modified-Since" 或 "If-None-Match" 暂时不走缓存
2、 客户端通过 cacheControl 指定了无缓存,不走缓存
3、客户端通过 cacheControl 指定了缓存,则看缓存过期时间,符合要求走缓存。

4、 如果走了网络请求,响应状态码为 304(只有客户端请求头包含 "If-Modified-Since" 或 "If-None-Match" ,服务器数据没变化的话会返回304状态码,不会返回响应内容), 表示客户端继续用缓存。

(策略模式:一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。)

源码中用到的几个重要的类及作用解释:

1.OkhttpClient :对外的API,OKHttp的很多功能模块,全部包装进这个类;创建分为两种:一种是new OkHttpClient()的方式,另一种是使用建造者(Builder)模式 -- new OkHttpClient.Builder()....Build()。那么这两种方式有什么区别呢?

第一种:new OkHttpClient(),OkHttp做了很多工作,很多我们需要的参数在这里都获得默认值,也就是默认值设定。

第二种:默认的设置和第一种方式相同,但是我们可以利用建造者模式单独的设置每一个属性;
注意事项:OkHttpClient强烈建议全局单例使用,因为每一个OkHttpClient都有自己单独的连接池和线程池,复用连接池和线程池能够减少延迟、节省内存。

2.RealCall类:集成Call类,从源代码中,可看到使用Call类,发送出(同步/异步)请求.RealCall的主要作用:发送请求,当中还有拦截器的建立过程,异步回调。

3.Dispatcher类(调度器,多线程):保存同步和异步Call的地方,并负责执行异步AsyncCall

4.拦截器链:有用户自定义的interceptor、retryAndFollowUpInterceptor、BridgeInterceptor、CacheInterceptor、ConnectInterceptor、 networkInterceptors、CallServerInterceptor。依次通过以上拦截器,传递给RealCall中的ApplicationInterceptorChain。拦截器之所以可以依次调用,并最终再从后先前返回Response,都依赖于ApplicatiionInterceptorChain的proceed方法.

5.HttpEngine类:OKhttp底层的实现,(还在看)

缓存策略:提到缓存策略,就要提到CacheInterceptor拦截器,如下图

CacheStrategy实现缓存策略,CacheStrategy使用Factory模式进行构造,该类决定是使用缓存还是使用网络请求

Cache是封装了实际的缓存操作;
DiskLruCache:Cache基于DiskLruCache;

线程池(同步,异步):

针对异步请求,Dispatcher使用了两个Deque,一个保存准备执行的请求,一个保存正在执行的请求,为什么要用两个呢?因为Dispatcher默认支持最大的并发请求是64个,单个Host最多执行5个并发请求,如果超过,则Call会先被放入到readyAsyncCall中,当出现空闲的线程时,再将readyAsyncCall中的线程移入到runningAsynCalls中,执行请求。

如果正在执行的请求总数<=64 && 单个Host正在执行的请求<=5,则将请求加入到runningAsyncCalls集合中,紧接着就是利用线程池执行该请求,否则就将该请求放入readyAsyncCalls集合中。

总结

【Android 详细知识点思维脑图(技能树)】

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

详细整理在石墨文档可以见;

Android架构视频+BAT面试专题PDF+学习笔记​

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

原文作者:茶卡y
原文链接:https://blog.csdn.net/u012881042/article/details/79759203

上一篇下一篇

猜你喜欢

热点阅读