Android知识点整理-网络

186 阅读7分钟

Okhttp

okhttp分发器和五大拦截器

  • 分发器:dispatcher

image.png 通过源码看到Dispatcher维护了三个ArrayDeque,一个保存了正在执行的同步任务;一个保存异步正在执行的请求,另一个是异步等待执行的请求,异步右两个ArrayDeque是因为Dispatcher默认支持最大的并发请求是64个,单个Host最多执行5个并发请求,如果超过,则Call会先被放入到readyAsyncCall中,当出现空闲的线程时,再将readyAsyncCall中的线程移入到runningAsynCalls中,执行请求。

  • 拦截器 1.RetryAndFollowUpInterceptor(重试并重定向拦截器)

2.BridgeInterceptor(桥梁拦截器)

3.CacheInterceptor(缓存拦截器)

4.ConnectInterceptor(连接拦截器)

5.CallServerInterceptor(呼叫服务器拦截器)

OKHttp的超时时间,有考虑DNS超时码

OkHttpClient的Builder类存在dns()方法可以设置一个Dns类型参数。 实现Dns接口,并在lookup实现超时逻辑

OkHttpClient.Builder builder = new OkHttpClient.Builder()
    .connectTimeout(timeout, TimeUnit.MILLISECONDS) 
    .dns(new XDns(timeout)) 
    .retryOnConnectionFailure(bRetry);

OKHttp线程池、连接池讲下

异步请求最大同时请求数量
private int maxRequests = 64;
异步请求同一域名同时存在的最大请求数量
private int maxRequestsPerHost = 5;

OKHttp请求失败了重试1、2次怎么做

自己实现一个RetryIntercepter中,通过response.isSuccessful()来对响应码进行判断,循环调用了多次chain.proceed(request)来实现重试拦截
设置重试3次,一共请求了4次(默认1次+重试3次)

OkHttp网络请求的整个流程

  • 创建请求对象 (url, method,body)-->request-->Call

  • 请求事件队列,线程池分发 enqueue-->Runnable-->ThreadPoolExecutor

  • 递归Interceptor拦截器,发送请求。 InterceptorChain

  • 请求回调,数据解析。 Respose-->(code,message,requestBody)

网络请求缓存处理,okhttp如何处理网络缓存的

要开启使用Okhttp的缓存其实很简单,只需要给OkHttpClient对象设置一个Cache对象即可,创建一个Cache时指定缓存保存的目录和缓存最大的大小即可。目前 OkHttp 不支持读取 Post 请求的缓存,post缓存需自实现。

//新建一个cache,指定目录为外部目录下的okhttp_cache目录,大小为100M
Cache cache = new Cache(new File(Environment.getExternalStorageDirectory() + "/okhttp_cache/"), 100 * 1024 * 1024);
将cache设置到OkHttpClient中,这样缓存就开始生效了。
OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();

其实控制缓存的消息头往往是服务端返回的信息中添加的如”Cache-Control:max-age=60”。所以,会有两种情况。

  1. 客户端和服务端开发能够很好沟通,按照达成一致的协议,服务端按照规定添加缓存相关的消息头。
  2. 客户端与服务端的开发根本就不是同一家公司,定义一个拦截器,人为地添加Response中的消息头,然后再传递给用户。 3.“负一生韶华”的想法:使用MMKV自定义一个缓存池,在请求前封装执行readCache,在网络请求结束后执行wirteCache,这样还可以实现post请求缓存,key使用url和请求参数拼接,如果请求参数包含文件则不使用缓存,这里意义不大并且使用md5的话消耗性能

Retrofit

www.jianshu.com/p/f57b7cdb1…

Retrofit主要实现机制、作用、原理?

Retrofit的功能是按照接口定义,自动定制Call网络工作对象

网络访问的不变性
对于网络访问来说,不变的是一定有一个实现网络访问的对象,Retrofit选用了自家的OkHttpClient,不过为了把Retrofit和OkHttp两个项目解耦合,Retrofit根据依赖倒置原则,定义了Retrofit自己的Call即retrofit2.call,并定义了操作网络请求的OkHttpCall

网络访问的易变性
对于网络访问来说,易变的是网络访问的url、请求方式(get/post等)、Http请求的Header设置与安全设置等,以及返回的数据类型。

针对易变的url和请求方式,Retrofit使用了方法注解的方式,可读性良好,扩展性优异,但这需要实现对接口函数中注解的解析,这样就有了ServiceMethod
针对Http请求的各种设置,其实Retrofit没做什么,因为Retrofit使用的OkHttp有拦截器机制,可以应付这种变化。
针对返回的数据类型,由于目标数据类型与业务有关,是不确定的,Retrofit无法提供一个万能的转换类,所以Retrofit提供了扩展接口,允许开发者自己定义ConverterFactory和Converter,去实现潜在的数据类型转换。

具体业务的不变性
对于具体业务来说,不变的是一定要有一个Call网络工作对象,所以Retrofit可以有一个生产对象的机制(像工厂一样)

具体业务的易变性
对于具体业务来说,易变的就是这个Call网络工作对象的类型,不仅有CallBacl回调、可能还有Flowable工作流、或者其他潜在的对象类型。

针对这种Call对象的易变性,Retrofit也是无法提供一个万能的实现类,所以也是提供了扩展解耦,允许开发者自己定义CallAdapterFactory和CallAdapter,去实现潜在的Call类型转换。

Retrofit 协程适配

.addCallAdapterFactory(KotlinCallAdapterFactory())

try catch可以直接获取到对象

addConverterFactory和addCallAdapterFactory

  • addConverterFactory:添加自定义的数据转换工厂
  • addCallAdapterFactory:添加自定义实体解析工程,可以把返回的数据自动解析成实体

Retrofit 动态代理

在Retrofit的create中会通过Proxy.newProxyInstance来为传入的Service接口类创建一个代理对象,而当代理对象调用函数时,会调用动态代理的invoke函数。而在invoke函数中,会通过调用loadServiceMethod函数,对Method中的注释进行解析,并且返回ServiceMethod对象,传入OkHttpCall中,构建OkHttp的请求。

网络优化

使用数据缓存优化

见《网络请求缓存处理,okhttp如何处理网络缓存的》

数据压缩

  1. 通常在post 请求体中加入gzip等压缩字段。浏览器在发送请求时都会带着Accept-Encoding头字段,里面是浏览器支持的压缩格式列表,例如 gzip、deflate、br 等,这样服务器就可以从中选择一种压缩算法,放进Content-Encoding响应头里,再把原数据压缩后发给浏览器。
  2. 一些媒体资源传输的时候也可以进行压缩,比如图片上传前进行压缩,我们可以通过luban库将本地的图片进行压缩,压缩后图片质量不变,加载压缩后的图片,再进行上传。

DNS 优化

  1. 由于进行网络请求,可能会遇到DNS被劫持和DNS解析缓慢,造成网络请求过于耗时。 可以采用HTTPDNS来绕过运营商服务器解析过程,从而降低平均访问时长,提高连接率,进而提高网络访问的速度。比如腾讯云的HttpDNS服务器或者阿里云的HttpDNS服务器
  2. 设置DNS延时时间

Okhttp,Retrofit,Easyhttp对比

  • Okhttp:就是个轮子,使用比较麻烦
  • Retrofit:自动定制Call对象,addConverterFactory添加自定义的数据转换工厂,addCallAdapterFactory:添加自定义实体解析工程,可以把返回的数据自动解析成实体
  • Easyhttp:这就不得不说轮子哥yyds,一个请求代表一个对象,通过类继承和实现的特性来对接口进行动态化配置。而 Retrofit 采用的是注解方式,缺点是灵活性极低,因为注解上面只能放常量,也就会限定你在注解上面的一切参数只能是事先定义好的,这对接口的动态化配置极不利的。优势:1.动态host,2.添加全局参数,3.请求缓存,4.下载校验,5.生命周期自动管控。缺点:缺少协程适配框架,得用withContext(Dispatchers.IO)+同步请求 来实现