网络底层库,它是基于http协议封装的一套请求客户端,虽然它也可以开线程,但根本上它更偏向真正的请求,跟HttpClient, HttpUrlConnection的职责是一样的。其中封装了网络请求get、post等底层操作的实现。
为什么要在项目中使用这个库?- OkHttp 提供了对最新的 HTTP 协议版本 HTTP/2 和 SPDY 的支持,这使得对同一个主机发出的所有请求都可以共享相同的套接字连接。
- 如果 HTTP/2 和 SPDY 不可用,OkHttp 会使用连接池来复用连接以提高效率。
- OkHttp 提供了对 GZIP 的默认支持来降低传输内容的大小。
- OkHttp 也提供了对 HTTP 响应的缓存机制,可以避免不必要的网络请求。
- 当网络出现问题时,OkHttp 会自动重试一个主机的多个 IP 地址。
get、post请求、上传文件、上传表单等等。
这个库的优缺点是什么,跟同类型库的比较?- 优点:在上面
- 缺点:使用的时候仍然需要自己再做一层封装。
OkHttp内部的请求流程:使用OkHttp会在请求的时候初始化一个Call的实例,然后执行它的execute()方法或enqueue()方法,内部最后都会执行到getResponseWithInterceptorChain()方法,这个方法里面通过拦截器组成的责任链,依次经过用户自定义普通拦截器、重试拦截器、桥接拦截器、缓存拦截器、连接拦截器和用户自定义网络拦截器以及访问服务器拦截器等拦截处理过程,来获取到一个响应并交给用户。其中,除了OKHttp的内部请求流程这点之外,缓存和连接这两部分内容也是两个很重要的点,掌握了这3点就说明你理解了OkHttp。
各个拦截器的作用:- interceptors:用户自定义拦截器
- retryAndFollowUpInterceptor:负责失败重试以及重定向
- BridgeInterceptor:请求时,对必要的Header进行一些添加,接收响应时,移除必要的Header
- CacheInterceptor:负责读取缓存直接返回(根据请求的信息和缓存的响应的信息来判断是否存在缓存可用)、更新缓存
- ConnectInterceptor:负责和服务器建立连接
ConnectionPool:
1、判断连接是否可用,不可用则从ConnectionPool获取连接,ConnectionPool无连接,创建新连接,握手,放入ConnectionPool。
2、它是一个Deque,add添加Connection,使用线程池负责定时清理缓存。
3、使用连接复用省去了进行 TCP 和 TLS 握手的一个过程。
- networkInterceptors:用户定义网络拦截器
- CallServerInterceptor:负责向服务器发送请求数据、从服务器读取响应数据
使用责任链模式实现拦截器的分层设计,每一个拦截器对应一个功能,充分实现了功能解耦,易维护。
手写拦截器? OKhttp针对网络层有哪些优化? 网络请求缓存处理,okhttp如何处理网络缓存的? HttpUrlConnection 和 okhttp关系? Volley与OkHttp的对比:Volley:支持HTTPS。缓存、异步请求,不支持同步请求。协议类型是Http/1.0, Http/1.1,网络传输使用的是 HttpUrlConnection/HttpClient,数据读写使用的IO。 OkHttp:支持HTTPS。缓存、异步请求、同步请求。协议类型是Http/1.0, Http/1.1, SPDY, Http/2.0, WebSocket,网络传输使用的是封装的Socket,数据读写使用的NIO(Okio)。 SPDY协议类似于HTTP,但旨在缩短网页的加载时间和提高安全性。SPDY协议通过压缩、多路复用和优先级来缩短加载时间。
Okhttp的子系统层级结构图如下所示:
网络配置层:利用Builder模式配置各种参数,例如:超时时间、拦截器等,这些参数都会由Okhttp分发给各个需要的子系统。 重定向层:负责重定向。 Header拼接层:负责把用户构造的请求转换为发送给服务器的请求,把服务器返回的响应转换为对用户友好的响应。 HTTP缓存层:负责读取缓存以及更新缓存。 连接层:连接层是一个比较复杂的层级,它实现了网络协议、内部的拦截器、安全性认证,连接与连接池等功能,但这一层还没有发起真正的连接,它只是做了连接器一些参数的处理。 数据响应层:负责从服务器读取响应的数据。 在整个Okhttp的系统中,我们还要理解以下几个关键角色:
OkHttpClient:通信的客户端,用来统一管理发起请求与解析响应。 Call:Call是一个接口,它是HTTP请求的抽象描述,具体实现类是RealCall,它由CallFactory创建。 Request:请求,封装请求的具体信息,例如:url、header等。 RequestBody:请求体,用来提交流、表单等请求信息。 Response:HTTP请求的响应,获取响应信息,例如:响应header等。 ResponseBody:HTTP请求的响应体,被读取一次以后就会关闭,所以我们重复调用responseBody.string()获取请求结果是会报错的。 Interceptor:Interceptor是请求拦截器,负责拦截并处理请求,它将网络请求、缓存、透明压缩等功能都统一起来,每个功能都是一个Interceptor,所有的Interceptor最 终连接成一个Interceptor.Chain。典型的责任链模式实现。 StreamAllocation:用来控制Connections与Streas的资源分配与释放。 RouteSelector:选择路线与自动重连。 RouteDatabase:记录连接失败的Route黑名单。
自己去设计网络请求框架,怎么做? 从网络加载一个10M的图片,说下注意事项? http怎么知道文件过大是否传输完毕的响应? 谈谈你对WebSocket的理解? WebSocket与socket的区别? 二、网络封装框架:Retrofit实现原理 这个库是做什么用的?Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。Retrofit 2.0 开始内置 OkHttp,前者专注于接口的封装,后者专注于网络请求的高效。
为什么要在项目中使用这个库?1、功能强大:
- 支持同步、异步
- 支持多种数据的解析 & 序列化格式
- 支持RxJava
2、简洁易用:
- 通过注解配置网络请求参数
- 采用大量设计模式简化使用
3、可扩展性好:
- 功能模块高度封装
- 解耦彻底,如自定义Converters
任何网络场景都应该优先选择,特别是后台API遵循Restful API设计风格 & 项目中使用到RxJava。
这个库的优缺点是什么,跟同类型库的比较?- 优点:在上面
- 缺点:扩展性差,高度封装所带来的必然后果,如果服务器不能给出统一的API形式,会很难处理。
Retrofit主要是在create方法中采用动态代理模式(通过访问代理对象的方式来间接访问目标对象)实现接口方法,这个过程构建了一个ServiceMethod对象,根据方法注解获取请求方式,参数类型和参数注解拼接请求的链接,当一切都准备好之后会把数据添加到Retrofit的RequestBuilder中。然后当我们主动发起网络请求的时候会调用okhttp发起网络请求,okhttp的配置包括请求方式,URL等在Retrofit的RequestBuilder的build()方法中实现,并发起真正的网络请求。
你从这个库中学到什么有价值的或者说可借鉴的设计思想?内部使用了优秀的架构设计和大量的设计模式,在我分析过Retrofit最新版的源码和大量优秀的Retrofit源码分析文章后,我发现,要想真正理解Retrofit内部的核心源码流程和设计思想,首先,需要对它使用到的九大设计模式有一定的了解,下面我简单说一说:
1、创建Retrofit实例:
- 使用建造者模式通过内部Builder类建立了一个Retroift实例。
- 网络请求工厂使用了工厂方法模式。
2、创建网络请求接口的实例:
- 首先,使用外观模式统一调用创建网络请求接口实例和网络请求参数配置的方法。
- 然后,使用动态代理动态地去创建网络请求接口实例。
- 接着,使用了建造者模式 & 单例模式创建了serviceMethod对象。
- 再者,使用了策略模式对serviceMethod对象进行网络请求参数配置,即通过解析网络请求接口方法的参数、返回值和注解类型,从Retrofit对象中获取对应的网络的url地址、网络请求执行器、网络请求适配器和数据转换器。
- 最后,使用了装饰者模式ExecuteCallBack为serviceMethod对象加入线程切换的操作,便于接受数据后通过Handler从子线程切换到主线程从而对返回数据结果进行处理。
3、发送网络请求:
- 在异步请求时,通过静态delegate代理对网络请求接口的方法中的每个参数使用对应的ParameterHanlder进行解析。
4、解析数据
5、切换线程:
- 使用了适配器模式通过检测不同的Platform使用不同的回调执行器,然后使用回调执行器切换线程,这里同样是使用了装饰模式。
6、处理结果
Android:主流网络请求开源库的对比(Android-Async-Http、Volley、OkHttp、Retrofit)https://www.jianshu.com/p/050c6db5af5a
三、响应式编程框架:RxJava实现原理 RxJava到底是什么?RxJava是基于Java虚拟机上的响应式扩展库,它通过使用可观察的序列将异步和基于事件的程序组合起来。 与此同时,它扩展了观察者模式来支持数据/事件序列,并且添加了操作符,这些操作符允许你声明性地组合序列,同时抽象出要关注的问题:比如低级线程、同步、线程安全和并发数据结构等。
为什么多次执行subscribeOn(),只有第一次有效?从上面的分析,我们可以很容易了解到被观察者被订阅时是从最外面的一层(ObservableSubscribeOn)通知到里面的一层(ObservableOnSubscribe),当连续执行了到多次subscribeOn()的时候,其实就是先执行倒数第一次的subscribeOn()方法,直到最后一次执行的subscribeOn()方法,这样肯定会覆盖前面的线程切换。
RxJava 变换操作符 map flatMap concatMap buffer?- map:【数据类型转换】将被观察者发送的事件转换为另一种类型的事件。
- flatMap:【化解循环嵌套和接口嵌套】将被观察者发送的事件序列进行拆分 & 转换 后合并成一个新的事件序列,最后再进行发送。
- concatMap:【有序】与 flatMap 的 区别在于,拆分 & 重新合并生成的事件序列 的顺序与被观察者旧序列生产的顺序一致。
- buffer:定期从被观察者发送的事件中获取一定数量的事件并放到缓存区中,然后把这些数据集合打包发射。
Glide是Android中的一个图片加载库,用于实现图片加载。
为什么要在项目中使用这个库?1、多样化媒体加载:不仅可以进行图片缓存,还支持Gif、WebP、缩略图,甚至是Video。
2、通过设置绑定生命周期:可以使加载图片的生命周期动态管理起来。
3、高效的缓存策略:支持内存、Disk缓存,并且Picasso只会缓存原始尺寸的图片,内Glide缓存的是多种规格,也就是Glide会根据你ImageView的大小来缓存相应大小的图片尺寸。
4、内存开销小:默认的Bitmap格式是RGB_565格式,而Picasso默认的是ARGB_8888格式,内存开销小一半。
这个库都有哪些用法?对应什么样的使用场景?1、图片加载:Glide.with(this).load(imageUrl).override(800, 800).placeholder().error().animate().into()。
2、多样式媒体加载:asBitamp、asGif。
3、生命周期集成。
4、可以配置磁盘缓存策略ALL、NONE、SOURCE、RESULT。
这个库的优缺点是什么,跟同类型库的比较?库比较大,源码实现复杂。
这个库的核心实现原理是什么?如果让你实现这个库的某些核心功能,你会考虑怎么去实现?- Glide&with:
1、初始化各式各样的配置信息(包括缓存,请求线程池,大小,图片格式等等)以及glide对象。
2、将glide请求和application/SupportFragment/Fragment的生命周期绑定在一块。
- Glide&load:
设置请求url,并记录url已设置的状态。
3、Glide&into:
1、首先根据转码类transcodeClass类型返回不同的ImageViewTarget:BitmapImageViewTarget、DrawableImageViewTarget。
2、递归建立缩略图请求,没有缩略图请求,则直接进行正常请求。
3、如果没指定宽高,会根据ImageView的宽高计算出图片宽高,最终执行到onSizeReay()方法中的engine.load()方法。
4、engine是一个负责加载和管理缓存资源的类
- 常规三级缓存的流程:强引用->软引用->硬盘缓存
当我们的APP中想要加载某张图片时,先去LruCache中寻找图片,如果LruCache中有,则直接取出来使用,如果LruCache中没有,则去SoftReference中寻找(软引用适合当cache,当内存吃紧的时候才会被回收。而weakReference在每次system.gc()就会被回收)(当LruCache存储紧张时,会把最近最少使用的数据放到SoftReference中),如果SoftReference中有,则从SoftReference中取出图片使用,同时将图片重新放回到LruCache中,如果SoftReference中也没有图片,则去硬盘缓存中中寻找,如果有则取出来使用,同时将图片添加到LruCache中,如果没有,则连接网络从网上下载图片。图片下载完成后,将图片保存到硬盘缓存中,然后放到LruCache中。
- Glide的三层缓存机制:
Glide的缓存机制,主要分为2种缓存,一种是内存缓存,一种是磁盘缓存。之所以使用内存缓存的原因是:防止应用重复将图片读入到内存,造成内存资源浪费。之所以使用磁盘缓存的原因是:防止应用重复的从网络或者其他地方下载和读取数据。正式因为有着这两种缓存的结合,才构成了Glide极佳的缓存效果。
Glide缓存机制大致分为三层:内存缓存、弱引用缓存、磁盘缓存。
取的顺序是:Lru 算法缓存(内存)、弱引用、磁盘。
存的顺序是:弱引用、Lru 算法缓存(内存)、磁盘。
三层存储的机制在Engine中实现的。先说下Engine是什么?Engine这一层负责加载时做管理内存缓存的逻辑。持有MemoryCache、Map
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?