volley的设计目标就是非常适合数据量小,通信量大的客户端,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。Volley停止了更新,而OkHttp得到了官方的认可,并在不断优化。因此我最终替换为了OkHttp
volley原理
主线程中调用RequestQueue的add()方法来添加一条网络请求,这条请求会先被加入到缓存队列当中,如果发现可以找到相应的缓存结果就直接读取缓存并解析,然后回调给主线程。如果在缓存中没有找到结果,则将这条请求加入到网络请求队列中,然后处理发送HTTP请求,解析响应结果,写入缓存,并回调主线程。
为什么说Volley适合数据量小,通信频繁的网络操作
volley中为了提高请求处理的速度,采用了ByteArrayPool进行内存中的数据存储的,如果下载大量的数据,这个存储空间就会溢出,所以不适合大量的数据,但是由于他的这个存储空间是内存中分配的,当存储的时候优是从ByteArrayPool中取出一块已经分配的内存区域, 不必每次存数据都要进行内存分配,而是先查找缓冲池中有无适合的内存区域,如果有,直接拿来用,从而减少内存分配的次数 ,所以他比较适合据量小,通信量大网络数据交互情况。
Retrofit原理
Retrofit 2.0底层依赖OkHttp实现,也就是说Retrofit本质上就是对OkHttp的更进一步封装,还支持Rxjava。Retrofit和其它Http库最大区别在于通过大范围使用注解简化Http请求。Retrofit使用注解来描述HTTP请求(请求方式、请求参数)。
内部也是调用okhttp的网络请求方式
Retrofit主要是在create方法中采用动态代理模式实现接口方法,这个过程构建了一个ServiceMethod对象,根据方法注解获取请求方式,参数类型和参数注解拼接请求的链接,当一切都准备好之后会把数据添加到Retrofit的RequestBuilder中。然后当我们主动发起网络请求的时候会调用okhttp发起网络请求,okhttp的配置包括请求方式,URL等在Retrofit的RequestBuilder的build()方法中实现,并发起真正的网络请求。
网络请求的工作本质上是OkHttp完成,而 Retrofit 仅负责网络请求接口的封装。
自己写网络请求框架
volley,okHttp等,这类优秀的框架其底层的实现大部分也是基于系统的 线程池 和 httpClient 或 HttpUrlConnection的网络请求类框架,Android中是不能在主线程中(又称UI线程)进行网络操作的,那么框架中必不可少地要使用到子线程,可以使用简单的 Thread + Runnable + Handler或者重量级点的AsyncTask。
处理好并发操作,一个应用中往往要进行多线程操作,而Java虚拟机对于一个线程的内存分配大约在1M左右,具体多少要看它执行的任务而定。所有就要使用线程池,例如newFixdThreadPool 可以控制并发数量,且在整个APP运行过程中有几个常驻线程在,避免使用时反复地new,退出时再销毁,而 newCacheThreadPool 则会在任务完成后,自动回收线程,它会帮你释放线程内存,也就不会有常驻线程。
还要注意使接口分离,降低耦合,而且接口能够我们带来很大的方便。
okhttp源码在构造器中利用建造者模式来构建 OkHttpClient 的对象,OkHttpClient 的构造器中主要是默认的配置。在newCall(Request request) (request是请求参数和URL)的时候,其实是里面创建了一个 RealCall 的对象,里面有execute() 方法。里面有getResponseWithInterceptorChain() ,添加了很多Interceptor,并返回 Response 对象的。
Interceptor 是 OkHttp 最核心的一个东西,它负责拦截请求进行一些额外的处理(例如 设置cookie),Interceptor有负责失败重试、重定向的(RetryAndFollowlnterceptor)、读取缓存、更新缓存的(Cachelnterceptor)、负责和服务器建立连接的(Connectlnterceptor)、负责向服务器发送请求数据(Bridgelnterceptor)、从服务器读取响应数据的(Networklnterceptor)。
每一个功能都只是一个 Interceptor,它们再连接成一个 Interceptor.Chain,环环相扣,最终完成一次网络请求。
根据响应码判断是否是重定向(3开头3xx)。RetryAndFollowUpInterceptor:如果不需要重定向,那么 followUp 为空,会释放资源,返回 response。 若为重定向就销毁旧连接,创建新连接,将重定向操作得到的新请求设置给 request。
同步请求通过Call.execute()直接返回当前的Response,而异步请求会把当前的请求Call.enqueue添加(AsyncCall)到请求队列中,并通过回调(Callback)的方式来获取最后结果。
@Override public Response execute() throws IOException { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); timeout.enter(); eventListener.callStart(this); try { client.dispatcher().executed(this); Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } catch (IOException e) { e = timeoutExit(e); eventListener.callFailed(this, e); throw e; } finally { client.dispatcher().finished(this); } } Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. List<Interceptor> interceptors = new ArrayList<>(); interceptors.addAll(client.interceptors()); interceptors.add(retryAndFollowUpInterceptor); interceptors.add(new BridgeInterceptor(client.cookieJar())); interceptors.add(new CacheInterceptor(client.internalCache())); interceptors.add(new ConnectInterceptor(client)); if (!forWebSocket) { interceptors.addAll(client.networkInterceptors()); } interceptors.add(new CallServerInterceptor(forWebSocket)); Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest, this, eventListener, client.connectTimeoutMillis(), client.readTimeoutMillis(), client.writeTimeoutMillis()); return chain.proceed(originalRequest); }