android volley 预研

来源:互联网 发布:python readline函数 编辑:程序博客网 时间:2024/06/08 08:15
最近想找一个好一点网络框架。所以在网上找了一堆资料,并看了一遍源码。
如下是拼凑的资料和看源码的过程笔记,以及提到的问题。


Volley简介

 

什么Volley?

在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于AsyncTaskLoaderHttpURLConnectionAsyncTaskHTTPClientApache)等,Google I/O 2013Volley发布。VolleyAndroid平台上的网络通信库,能使网络通信更快,更简单,更健壮。

 

Volley提供的功能

简单的讲,提供了如下主要的功能:

1、封装了的异步的request请求API

2、一个优雅和稳健的请求队列;

3、一个可扩展的架构,它使开发人员能够实现自定义的请求和响应处理机制;

4、能够使用外部HTTP Client库;

5、缓存策略;

6、自定义的网络图像加载视图(NetworkImageViewImageLoader);

 

 

Volley使用

    示例代码:

mQueue = Volley.newRequestQueue(getApplicationContext());

mQueue.add(new StringRequest(Method.GET, "http://www.baidu.com/", 

new Listener(){ 

@Override 

public void onResponse(String arg0) { 

// TODO Auto-generated method stub 

Log.e("onResponse", arg0); 

}, new ErrorListener(){ 

@Override 

public void onErrorResponse(VolleyError arg0) { 

// TODO Auto-generated method stub 

Log.e("onErrorResponse", arg0.toString()); 

})); 

//mQueue.start(); 此处需要,因为newRequest时候自动调了这个start

    首先,通过Volley的静态方法new一个请求队列,调用请求队列(RequestQueue是由缓存和网络线程构造的)start方法。

然后,得到一个RequestQueue请求队列时,就添加一个请求Request,Volley提供有三种请求的封装,一个是StringRequest,一个事ImageRequest,还有一个是JsonRequest

最后,add执行。

 

     RequestQueue的成员方法主要有下面几个:

 1.public void start();//请求队列开始进行调度发vgm

 2.public void stop();//队列退出调度

 3.public Request add(Request request);//添加一个请求,通过调用start()来执行

 4.void finish(Request request);//这个方法应该是释放请求资源的方法

 5.public void cancelAll();//取消当前的请求

 

 

以下是Volley的异常列表:

AuthFailureError:如果在做一个HTTP的身份验证,可能会发生这个错误。

NetworkErrorSocket关闭,服务器宕机,DNS错误都会产生这个错误。

NoConnectionError:和NetworkError类似,这个是客户端没有网络连接。

ParseError:在使用JsonObjectRequestJsonArrayRequest时,如果接收到的JSON是畸形,会产生异常。

SERVERERROR:服务器的响应的一个错误,最有可能的4xx5xx HTTP状态代码。

TimeoutErrorSocket超时,服务器太忙或网络延迟会产生这个异常。默认情况下,Volley的超时时间为2.5秒。如果得到这个错误可以使用RetryPolicy

 

 

Volley分析

 

public class Volley

四个静态newRequestQueue接口

public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes);

 

核心代码:

可以看到。在2.3之前用的是http client,之后用的httpurlconnection

if (Build.VERSION.SDK_INT >= 9) {

            stack = new HurlStack();

        } else { 

stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));

}

 

Network network = new BasicNetwork(stack);

RequestQueue queue;

if (maxDiskCacheBytes <= -1){

queue = new RequestQueue(new DiskBasedCache(cacheDir), network);

}else{

queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);

        }

 

        queue.start();

        return queue;

 

解释

创建一个stack = new HurlStack();负责封装,发送,接收。

Network network = new BasicNetwork(stack); 负责线程里执行。比httpstack不同在于,加入缓存头,调用httpstack,结果返回状态处理。302 401

queue = new RequestQueue(new DiskBasedCache(cacheDir), network);

queue.start();

 

 

 

public class HurlStack implements HttpStack

负责协议的拼装,发送,接收。

关键函数

1.public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)

2.private static HttpEntity entityFromConnection(HttpURLConnection connection)组装返回用:HttpResponse.setEntity()

3.protected HttpURLConnection createConnection(URL url)

4.private HttpURLConnection openConnection(URL url, Request<?> request)打开链接,设置超时等,并确定是否https

5.static void setConnectionParametersForRequest(HttpURLConnection connection, Request<?> request)设置参数

6.private static void addBodyIfExists(HttpURLConnection connection, Request<?> request)POSTPUTPATCH方式的内容拼装

 

 

public class BasicNetwork implements Network:

负责线程里执行。比httpstack不同在于,加入缓存头,调用httpstack,结果返回状态处理。302 401

关键函数:

public NetworkResponse performRequest(Request<?> request) throws VolleyError:唯一执行接口。返回NetworkResponse

Map<String, String> headers = new HashMap<String, String>();

    addCacheHeaders(headers, request.getCacheEntry());

    httpResponse = mHttpStack.performRequest(request, headers);

    StatusLine statusLine = httpResponse.getStatusLine();

int statusCode = statusLine.getStatusCode();

//错误处理有针对401.403这里不太符合我们的需求但不影响。

return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);

返回内容。

 

private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry):添加缓存入口。写到头用。

 

 

public class NetworkResponse

BasicNetwork解析后的结果

this.statusCode = statusCode;

    this.data = data;

    this.headers = headers;

    this.notModified = notModified;

    this.networkTimeMs = networkTimeMs;

 

 

public class RequestQueue

管理队列

private final Map<String, Queue<Request<?>>> mWaitingRequests:在add增加或修改。在finishremove

private final Set<Request<?>> mCurrentRequestsadd,cancelAll,finish

 

构建分发器部件

private final PriorityBlockingQueue<Request<?>> mCacheQueue

private final PriorityBlockingQueue<Request<?>> mNetworkQue:不缓存增加 

private final Cache mCache;缓存。

private final Network mNetwork;

private final ResponseDelivery mDelivery

;

两个分发器:

private NetworkDispatcher[] mDispatchers;相当于线程池,制定,默认4

private CacheDispatcher mCacheDispatcher;缓存分发

new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);

NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery);

 

一个自增计数

private AtomicInteger mSequenceGeneratorrequest.setSequence(getSequenceNumber());

 

说明:之所以没有用线程池等,完全是因为PriorityBlockingQueue所致!所以看到代码不是特别爽。建议大家看一下:java.util.concurrent包。

 

 

public abstract class Request<T> implements Comparable<Request<T>>

请求基类一切皆源于

 

 

public class NetworkDispatcher extends Thread 

网络下载部分

@Override

    public void run() {

  Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

        while (true) {

request = mQueue.take();

NetworkResponse networkResponse = mNetwork.performRequest(request);

Response<?> response = request.parseNetworkResponse(networkResponse);

mDelivery.postResponse(request, response);

}

}

 

 

public class AndroidAuthenticator implements Authenticator

用户token管理

 

public class ImageRequest extends Request<Bitmap>

一个实例化的图片请求

 

public class ImageLoader 

图片加载和缓存.很简洁的一个使用

 

public class NetworkImageView extends ImageView 

图片加载视图调用ImageLoader加载图片

 

 

关于cookie,编码格式,参数设置等::

 

StringRequest request= new StringRequest(Method.POST, url,

 this, this) {

@Override

protected Response<String> parseNetworkResponse(

NetworkResponse response) {

// TODO Auto-generated method stub

try {

 

Map<String, String> responseHeaders = response.headers;

String rawCookies = responseHeaders.get("Set-Cookie");

String dataString = new String(response.data, "UTF-8");

return Response.success(dataString,HttpHeaderParser.parseCacheHeaders(response));

} catch (UnsupportedEncodingException e) {

return Response.error(new ParseError(e));

}

 

public Map<String, String> getHeaders() throws AuthFailureError {

HashMap localHashMap = new HashMap();

localHashMap.put("Cookie", "你的cookie");

return localHashMap;

}

//设置post参数

protected Map<String, String> getParams() {

if(params==null){

return new HashMap<String, String>();

}

 return params;

}

                

//设置编码格式

@Override

protected Response<String> parseNetworkResponse(

NetworkResponse response) {

// TODO Auto-generated method stub

try {

String dataString = new String(response.data, "UTF-8");

return Response.success(dataString,HttpHeaderParser.parseCacheHeaders(response));

} catch (UnsupportedEncodingException e) {

return Response.error(new ParseError(e));

}

 

};

 

后记:

1.不适合大数据传输。所以对于大数据需要自己写请求,比如往上发图片,下载安装包,大文件等。其实对于单独安装包,大文件,android是有提供工具的,2.3引入了DownloadManager可以处理复杂的文件下载,

2.对于Requestqueue,建议部分考虑全局单例。 因为线程开启关闭是要浪费资源的。默认是开5线程(一个缓存,四个网络请求)。

3.缓存会导致newRequestQueue创建非常的慢,有人说达到十几秒。解决方案:有人在stackoverflow中提到过这个问题,然后他给出了解决方案。在initialize中,给FileOutputStream在套一层BufferedOutputStream。本人测试过,速度有十倍的提升。基本能控制初始化的时间在1-3s。另一个方案是全局一个requestqueue.

0 0