Volley 解析

时间:2022-09-03 13:16:28

Volley

Volley 解析

Volley 解析

Request处理流程

RequestQueue类中有三个基本的队列。调用RequestQueue.add(request)增加的请求会先增加mCacheQueue(优先级堵塞队列)由CacheDispatcher( 循环读取队列中的请求,当没有请求处理时线程堵塞)线程处理。假设该请求之前已经被缓存。读取缓存返回给主线程结果。否则将请求增加mNetworkQueue由NetworkDispatcher线程处理。

因为处理网络请求比較耗时。NetworkDispatcher线程默认开启四个。

每一个线程都循环从mNetworkQueue读取请求。运行HTTP请求并解析server返回结果,将结果存入缓存,同一时候向通过handler回调到主线程,向用户返回结果。

假设该请求不是第一次处理。在进入mCacheQueue之前,可能回被增加mWaitingRequests(假设有同样url的请求正在处理)。作用是避免反复的请求多次运行,提高请求速度。当请求处理完之后,会检查mWaitingRequests是否有等待的请求。并所有增加缓存队列。

mCacheQueue :PriorityBlockingQueue<Request<?

>>

mNetworkQueue:PriorityBlockingQueue<Request<?>>

mWaitingRequests: Map<String,Queue<Request<?>>

怎样推断缓存是否过期

Expires首部和Cache-Control:max-age首部都是来告诉缓存文档有没有过期。Volley提供的解析类HttpHeaderParser在解析HTTP返回结果时。会从返回头中获取Expires和Cache-Control:max-age相关信息并存储在缓存数据中。假设没有过期还要推断是否须要刷新。一般假设数据没有过期是不须要刷新的。可是假设返回头中包括stale-while-revalidate会将数据提交给用户后请求刷新数据。在实现Request类的抽象方法parseNetworkResponse时,用户必须调用HttpHeaderParser.parseCacheHeaders解析返回头,否则无法推断缓存是否过期。

运行网络请求

假设sdk版本号大于9使用HttpURLConnection运行网络请求,否则使用HttpClient。由BasicNetwork的

performRequest方法运行网络请求。在performRequest会调用Request类的getHeaders获取请求头。

假设server返回的响应头中包括Last-Modified或ETag,在运行下次请求时会在请求头中增加If-None-Match或If-Modified-Since。

假设server上的内容没有改变,会返回304状态。不会返回内容。内容从缓存获取。

自己定义Request

Volley 解析

Request类是一个泛型类,当中T用户期望带到的数据类型。Volley已经提供了StringRequest、ImageRequest、JosnObjectRequest等能够将server返回的数据解析为String、Image JSONObject。可是这些Request有时候不能满足用户的需求。

比方假设server返回

Xml格式的数据,server返回的Josn用户不想解析为JosnObject。

能够很方便的对Volley的Request进行扩展。主要是继承Request。重写parseNetworkResponse和deliverResponse方法在parseNetworkResponse中将返回二进制数据转化为须要的数据格式。同一时候调用HttpHeaderParser.parseCacheHeaders得到缓存数据。

在deliverResponse中调用Listenner返回结果。

假设要更改Http的请求头或者在post方法中须要提供数据须要重写getHeaders和getParams方法。

Request实现了Comparable,存储Request使用的是优先级队列。能够对Reqest设定优先级。有LOW,NORMAL,HIGH,IMMEDIATE四中优先级。

默认使用NORMAL。ImageRequest使用的是LOW。

public class GsonRequest<T> extends Request<T> {
private final Listener<T> mListener;
private Gson mGson;
private Class<T> mClass;
public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener,
ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
mClass = clazz;
mListener = listener;
}
public GsonRequest(String url, Class<T> clazz, Listener<T> listener,
ErrorListener errorListener) {
this(Method.GET, url, clazz, listener, errorListener);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(mGson.fromJson(jsonString, mClass),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
}

NetworkImageView 载入图片

NetworkImageView必须配合ImageLoader使用。ImageLoader能够依据url异步载入图片。ImageLoader内部使用ImageRequest载入图片,同一时候对会把同样的请求进行合并降低请求次数。

多个NetworkImageView相应一个ImageLoader。

假设有多个NetworkImageView同一时候请求同一个图片。ImageLoader仅仅会运行一次网络请求。

ImageLoader内部定义了一个接口,该接口的实现由用户提供。该接口用来缓存图片,一般的实现都使用了LRU算法。

public class BitmapLruCache extends LruCache<String, Bitmap> implements ImageLoader.ImageCache {
public static final int ONE_MB = 1048576;
public BitmapLruCache(Context context) {
super(1048576 * ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass() / 10);
}
protected int sizeOf(String key, Bitmap value) {
return Build.VERSION.SDK_INT >= 12?value.getByteCount():value.getRowBytes() * value.getHeight();
}
public Bitmap getBitmap(String url) {
return (Bitmap)this.get(url);
}
public void putBitmap(String url, Bitmap bitmap) {
this.put(url, bitmap);
}
}

加上Volley提供的磁盘缓存。NetworkImageView载入图片使用了两级缓存。

  1. 创建ImageLoader

    mLoader = new ImageLoader(Volley.newRequestQueue(context), new BitmapLruCache(context));

  2. 载入图片

    imageView.setImageUrl(girl.getImg(), mLoader);

还能够通过imageView.setDefaultImageResId()来设置图片未载入时显示的默认图片。通过imageView.setErrorImageResId()来设置图片载入失败显示的图片。NetworkImageView会在url地址改变之后会及时取消之前的载入。

Volley 缓存

Volley默认会缓存请求结果。缓存存放在应用的volley文件夹。每一个请求结果相应一个文件。文件名称由url的hash码得到。默认缓存大小为5M。

没有提供更改缓存大小的接口。假设更改大小必须更改代码。缓存採用LUR算法。

内部主要由LinkedHashMap实现。LinkedHashMap内部有一个双向链表和一个HashMap,链表用来保存元素的存储顺序,MAP用来高速存取元素。

private final Map<String, CacheHeader> mEntries =new LinkedHashMap<String, CacheHeader>(16, .75f, true)

必须将LinkedHashMap的第三个參数设为true。LinkedHashMap才会按訪问顺序排序(最少被訪问的entry靠前,近期訪问的entry靠后)。

每次在增加元素时。都会推断缓存大小是否超过5M,假设超过调用pruneIfNeeded将最老的元素移除。缓存文件时,会缓存server返回的http头和body。

Retrofit

Retrofit注解

Retrofit的Annotation包括请求方法相关的@GET、@POST、@HEAD、@PUT、@DELETA、@PATCH。和參数相关的@Path、@Field、@Multipart等。

  • 通过注解指定请求url,方法和參数

    @GET("group/{id}/users")

    Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
  • 指定请求头

    @Headers("Cache-Control: max-age=640000")

    @GET("widget/list")

    Call<List<Widget>> widgetList();
  • 指定field

    @FormUrlEncoded

    @POST("user/edit")

    Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last)
  • 指定Http body

    @POST("users/new")

    Call<User> createUser(@Body User user);//必须有相应的Converter

    通用的header能够在okhttp的Interceptors中设定。

使用步骤

1.定义接口

public interface Api {

@GET("tnfs/api/list")

Call<Gallery> getList(@Query(ID) int id, @Query(PAGE) int page, @Query(ROWS) int rows);

}

2.生成对象

public static  Api getApi(){
Retrofit retrofit=new Retrofit.Builder().baseUrl(BASEURL) //设置域名
.addConverterFactory(GsonConverterFactory.create())//增加Converter
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//与RxJava整合时须要增加
.build();
return retrofit.create(Api.class);
}

Converter用于将请求结果转化成须要的数据。如GsonConverter将JSON请求结果用Gson解析成Java对象。Retrofit提供的Converter

  • Gson: com.squareup.retrofit2:converter-gson
  • Jackson: com.squareup.retrofit2:converter-jackson
  • Moshi: com.squareup.retrofit2:converter-moshi
  • Protobuf: com.squareup.retrofit2:converter-protobuf
  • Wire: com.squareup.retrofit2:converter-wire
  • Simple XML: com.squareup.retrofit2:converter-simplexml
  • Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

3.调用接口

异步调用

NetworkApi.getApi().getList(mId,1,8).enqueue(new Callback<Gallery>() {
@Override
public void onResponse(Response<Gallery> response, Retrofit retrofit) {
mAdapter.setItemList(response.body().getList());
}
@Override
public void onFailure(Throwable t) {
}
});

同步调用

Callery gallery= NetworkApi.getApi().getList(mId,1,8).excute();

Retrofit + RxJava

方法的返回类型定义为Observable

Observable<Gallery> getList(@Query(ID) int id, @Query(PAGE) int page, @Query(ROWS) int rows);

须要增加addCallAdapterFactory(RxJavaCallAdapterFactory.create()才干够识别Observable接口。

NetworkApi.getApi().getList(mId,1,8).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Gallery>() {
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {}
@Override
public void onNext(Gallery gallery) {}
});

实现原理

使用OKHTTP运行网络请求

使用动态代理为接口生成实现类。

代理模式介绍

Volley 解析

主要作用

1. 方法增强

你能够在不改动源代码的情况下,增强一些方法,在方法运行前后做不论什么你想做的事情。比方。比方能够增加调用日志。做事务控制等。

2. 远程调用

Android中的跨进程通信。

服务端为实现类。client为代理类。实现同样的接口可是代理类并不须要实现接口定义的功能。

而是使用binder机制向服务端发起请求,服务端返回结果给client。

服务端和client还能够跨网络。

动态代理

为某个类自己主动产生代理类。该类必须实现一个接口。

原理

在运行时自己主动产生代码并进行编译,然后用classloader载入字节码生成Class类,用反射调用Class类的构造函数生成对象。

public class CachedProviderHandler implements InvocationHandler {
private Map<String, Object> cached = new HashMap<>();
private Object target; public CachedProviderHandler(Object target) {
this.target = target;
} public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Type[] types = method.getParameterTypes();
if (method.getName().matches("get.+") && (types.length == 1) &&
(types[0] == String.class)) {
String key = (String) args[0];
Object value = cached.get(key);
if (value == null) {
value = method.invoke(target, args);
cached.put(key, value);
}
return value;
}
return method.invoke(target, args);
}
} public abstract class ProviderFactory {
public static FontProvider getFontProvider() {
Class<FontProvider> targetClass = FontProvider.class;
return (FontProvider) Proxy.newProxyInstance(targetClass.getClassLoader(),
new Class[] { targetClass },
new CachedProviderHandler(new FontProviderFromDisk()));
}
}

怎样自己主动产生代码

// 假设需代理接口 Simulator
public interface Simulator {
short simulate(int arg1, long arg2, String arg3) throws ExceptionA, ExceptionB;
} // 假设代理类为 SimulatorProxy, 其类声明将例如以下
final public class SimulatorProxy implements Simulator { // 调用处理器对象的引用
protected InvocationHandler handler; // 以调用处理器为參数的构造函数
public SimulatorProxy(InvocationHandler handler){
this.handler = handler;
} // 实现接口方法 simulate
public short simulate(int arg1, long arg2, String arg3)
throws ExceptionA, ExceptionB { // 第一步是获取 simulate 方法的 Method 对象
java.lang.reflect.Method method = null;
try{
method = Simulator.class.getMethod(
"simulate",
new Class[] {int.class, long.class, String.class} );
} catch(Exception e) {
// 异常处理 1(略)
} // 第二步是调用 handler 的 invoke 方法分派转发方法调用
Object r = null;
try {
r = handler.invoke(this,
method,
// 对于原始类型參数须要进行装箱操作
new Object[] {new Integer(arg1), new Long(arg2), arg3});
}catch(Throwable e) {
// 异常处理 2(略)
}
// 第三步是返回结果(返回类型是原始类型则须要进行拆箱操作)
return ((Short)r).shortValue();
}
}

Volley vs Retrofit

  • Retrofit更好用
  • Volley提供了载入图片的支持
  • Volley有缓存,Retrofit能够借助Okhttp提供缓存
  • Volley因为仅仅有四个线程,缓存默认仅仅有5M不适合大文件处理

參考

http://gank.io/post/560e15be2dca930e00da1083#toc_26

给 Android 开发人员的 RxJava 具体解释

http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html

Java 动态代理机制分析及扩展

http://square.github.io/retrofit/

Retrofit官网

Volley 解析的更多相关文章

  1. Volley解析(一)--Volley的使用

    Volley解析(一)--Volley的使用 Volley 是一个HTTP协议的网络请求框架 Volley的优势: 自动安排网络请求 支持多个并发网络连接 具有标准HTTP缓存一致性的透明磁盘和内存响 ...

  2. Volley解析之表单提交篇

    要实现表单的提交,就要知道表单提交的数据格式是怎么样,这里我从某知名网站抓了一条数据,先来分析别人提交表单的数据格式.  数据包: Connection: keep-alive Content-Len ...

  3. Android -- Volley解析

    Volley设计 Dispatch Thread不断从RequestQueue中取出请求,根据是否已缓存调用Cache或Network这两类数据获取接口之一,从内存缓存或是服务器取得请求的数据,然后交 ...

  4. volley源代码解析&lpar;七&rpar;--终于目的之Response&amp&semi;lt&semi;T&amp&semi;gt&semi;

    在上篇文章中,我们终于通过网络,获取到了HttpResponse对象 HttpResponse是android包里面的一个类.然后为了更高的扩展性,我们在BasicNetwork类里面看到.Volle ...

  5. Google官方网络框架-Volley的使用解析Json以及加载网络图片方法

    Google官方网络框架-Volley的使用解析Json以及加载网络图片方法 Volley是什么? Google I/O 大会上,Google 推出 Volley的一个网络框架 Volley适合什么场 ...

  6. android解析xml一直报错org&period;xmlpull&period;v1&period;XmlPullParserException

     错误: org.xmlpull.v1.XmlPullParserException: Unexpected token (position:TEXT @1:2 injava.io.String ...

  7. 温故而知新 Volley源码解读与思考

    相比新的网络请求框架Volley真的很落后,一无是处吗,要知道Volley是由google官方推出的,虽然推出的时间很久了,但是其中依然有值得学习的地方.  从命名我们就能看出一些端倪,volley中 ...

  8. Android JSON解析库Gson和Fast-json的使用对比和图书列表小案例

    Android JSON解析库Gson和Fast-json的使用对比和图书列表小案例 继上篇json解析,我用了原生的json解析,但是在有些情况下我们不得不承认,一些优秀的json解析框架确实十分的 ...

  9. Android JSON原生解析的几种思路,以号码归属地,笑话大全,天气预报为例演示

    Android JSON原生解析的几种思路,以号码归属地,笑话大全,天气预报为例演示 今天项目中要实现一个天气的预览,加载的信息很多,字段也很多,所以理清了一下思路,准备独立出来写一个总结,这样对大家 ...

随机推荐

  1. PHP5&period;6启动失败

    PHP编译安装完毕,启动失败,提示 1 [23-Jun-2014 12:27:02] ERROR: failed to open configuration file '/usr/local/php/ ...

  2. iOS开发之CocoaLumberjack

    Cocoa LumberJack是一个功能强大的NSlog,是通用的Cocoa日志框架之一.它可以提供更高级的log功能,比如记录log至文件或网络,并可根据log的级别(info.debug.war ...

  3. window&period;location&period;href 和 window&period;location&period;replace 的区别

    window.location.href  和  window.location.replace 的区别 1.window.location.href=“url”:改变url地址: 2.window. ...

  4. Following a Select Statement Through Postgres Internals

    This is the third of a series of posts based on a presentation I did at the Barcelona Ruby Conferenc ...

  5. 【Catalina】

    Tomcat's servlet container was redesigned as Catalina in Tomcat version 4.x. The architect for Catal ...

  6. Amazon API Gateway Importer整合过程小结

    (1)需要将swagger json转换成amazon api gateway 所需要的格式(根据Method Request中 Request PathsURL Query String Param ...

  7. codevs 1282 约瑟夫问题(线段树)

    #include<iostream> #include<cstdio> #include<cstring> #define maxn 30010 using nam ...

  8. oralce

    1.对数据库SQL2005.ORACLE熟悉吗?   SQL2005是微软公司的数据库产品.是一个RDBMS数据库,一般应用在一些中型数据库的应用,不能跨平台.   ORACLE是ORACLE公司的数 ...

  9. 我推荐的 Java Web 学习路线

    晚上再 V2 的 Java 的节点看到有人问 Java Web 书籍推荐.我这半年多的时间,也从别的方向开始转向 Java 服务端开发,所以,我来说下我的学习路线,帮助有需要的朋友把半只脚踏进 Spr ...

  10. Java——重载和重写

    前言 在程序设计中经常会遇到对对方法的重载或者重写,下面将介绍重载和重写. 重载(Overloade) 重载出现的原因 任何程序设计语言都具备的一项重要特性就是对名字的运用.当创建一个对象时,就给对象 ...