Android Volley 是Google开发的一个网络lib,可以让你更加简单并且快速的访问网络数据。Volley库的网络请求都是异步的,你不必担心异步处理问题。

Volley的优点:

  1. 请求队列和请求优先级
  2. 请求Cache和内存管理
  3. 扩展性性强
  4. 可以取消请求

##下载和编译volley.jar

  • 需要安装git,ant,android sdk

clone代码:
git clone https://android.googlesource.com/platform/frameworks/volley

  • 编译jar:
    android update project -p . ant jar

  • 添加volley.jar到你的项目中 不过已经有人将volley的代码放到github上了:
    https://github.com/mcxiaoke/android-volley,你可以使用更加简单的方式来使用volley:

    ###Maven

    format: jar

    <span class="tag"><<span class="title">dependency</span>></span>
        <span class="tag"><<span class="title">groupId</span>></span>com.mcxiaoke.volley<span class="tag"></<span class="title">groupId</span>></span>
        <span class="tag"><<span class="title">artifactId</span>></span>library<span class="tag"></<span class="title">artifactId</span>></span>
        <span class="tag"><<span class="title">version</span>></span>1.0.6<span class="tag"></<span class="title">version</span>></span>
    <span class="tag"></<span class="title">dependency</span>></span>
    

    ###Gradle

    format: jar

    compile 'com.mcxiaoke.volley:library:1.0.6'

    ##Volley工作原理图
    Volley{.fancybox}

    ##创建Volley 单例
    使用volley时,必须要创建一个请求队列RequestQueue,使用请求队列的最佳方式就是将它做成一个单例,整个app使用这么一个请求队列。

    <span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AppController</span> <span class="keyword">extends</span> <span class="title">Application</span> </span>{
    
    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = AppController.class
            .getSimpleName();
    
    <span class="keyword">private</span> RequestQueue mRequestQueue;
    <span class="keyword">private</span> ImageLoader mImageLoader;
    
    <span class="keyword">private</span> <span class="keyword">static</span> AppController mInstance;
    
    <span class="annotation">@Override</span>
    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">()</span> </span>{
        <span class="keyword">super</span>.onCreate();
        mInstance = <span class="keyword">this</span>;
    }
    
    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> AppController <span class="title">getInstance</span><span class="params">()</span> </span>{
        <span class="keyword">return</span> mInstance;
    }
    
    <span class="function"><span class="keyword">public</span> RequestQueue <span class="title">getRequestQueue</span><span class="params">()</span> </span>{
        <span class="keyword">if</span> (mRequestQueue == <span class="keyword">null</span>) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }
    
        <span class="keyword">return</span> mRequestQueue;
    }
    
    <span class="function"><span class="keyword">public</span> ImageLoader <span class="title">getImageLoader</span><span class="params">()</span> </span>{
        getRequestQueue();
        <span class="keyword">if</span> (mImageLoader == <span class="keyword">null</span>) {
            mImageLoader = <span class="keyword">new</span> ImageLoader(<span class="keyword">this</span>.mRequestQueue,
                    <span class="keyword">new</span> LruBitmapCache());
        }
        <span class="keyword">return</span> <span class="keyword">this</span>.mImageLoader;
    }
    
    <span class="keyword">public</span> <T> <span class="function"><span class="keyword">void</span> <span class="title">addToRequestQueue</span><span class="params">(Request<T> req, String tag)</span> </span>{
        <span class="comment">// set the default tag if tag is empty</span>
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }
    
    <span class="keyword">public</span> <T> <span class="function"><span class="keyword">void</span> <span class="title">addToRequestQueue</span><span class="params">(Request<T> req)</span> </span>{
        req.setTag(TAG);
        getRequestQueue().add(req);
    }
    
    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">cancelPendingRequests</span><span class="params">(Object tag)</span> </span>{
        <span class="keyword">if</span> (mRequestQueue != <span class="keyword">null</span>) {
            mRequestQueue.cancelAll(tag);
        }
    }
    }
    

    另外,你还需要一个Cache来存放请求的图片:

    <span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LruBitmapCache</span> <span class="keyword">extends</span> <span class="title">LruCache</span><<span class="title">String</span>, <span class="title">Bitmap</span>> <span class="title">implement</span> <span class="title">ImageCache</span> </span>{
        <span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">int</span> <span class="title">getDefaultLruCacheSize</span><span class="params">()</span> </span>{
            <span class="keyword">final</span> <span class="keyword">int</span> maxMemory = (<span class="keyword">int</span>) (Runtime.getRuntime().maxMemory() / <span class="number">1024</span>);
            <span class="keyword">final</span> <span class="keyword">int</span> cacheSize = maxMemory / <span class="number">8</span>;
    
            <span class="keyword">return</span> cacheSize;
        }
    
        <span class="function"><span class="keyword">public</span> <span class="title">LruBitmapCache</span><span class="params">()</span> </span>{
            <span class="keyword">this</span>(getDefaultLruCacheSize());
        }
    
        <span class="function"><span class="keyword">public</span> <span class="title">LruBitmapCache</span><span class="params">(<span class="keyword">int</span> sizeInKiloBytes)</span> </span>{
            <span class="keyword">super</span>(sizeInKiloBytes);
        }
    
        <span class="annotation">@Override</span>
        <span class="keyword">protected</span> <span class="function"><span class="keyword">int</span> <span class="title">sizeOf</span><span class="params">(String key, Bitmap value)</span> </span>{
            <span class="keyword">return</span> value.getRowBytes() * value.getHeight() / <span class="number">1024</span>;
        }
    
        <span class="annotation">@Override</span>
        <span class="keyword">public</span> <span class="function">Bitmap <span class="title">getBitmap</span><span class="params">(String url)</span> </span>{
            <span class="function"><span class="keyword">return</span> <span class="title">get</span><span class="params">(url)</span></span>;
        }
    
        <span class="annotation">@Override</span>
        <span class="keyword">public</span> <span class="function"><span class="keyword">void</span> <span class="title">putBitmap</span><span class="params">(String url, Bitmap bitmap)</span> </span>{
            put(url, bitmap);
        }
    }
    

    别忘记在AndroidManifest.xml文件中添加android.permission.INTERNET权限。

    ##创建Json请求
    volley自带了JsonObjectRequestJsonArrayRequest分别来处理Json对象请求和Json数据请求(但是voley没有使用gson库写一个GsonRequest,发送一个request,volley直接返回一个java对象,不过我们可以自己写)。

    ###创建json object请求
    发送一个请求只要这么简单,创建一个JsonRequest对象,写好response回调接口,并把这个请求放到请求队列中就可以了。JsonArrayRequest也类似。

    <span class="comment">// Tag used to cancel the request</span>
    String tag_json_obj = <span class="string">"json_obj_req"</span>;
    String url = <span class="string">"http://api.androidhive.info/volley/person_object.json"</span>;
    
    JsonObjectRequest jsonObjReq = <span class="keyword">new</span> JsonObjectRequest(Method.GET,url, <span class="keyword">null</span>,
                <span class="keyword">new</span> Response.Listener<JSONObject>() {
    
                    <span class="annotation">@Override</span>
                    <span class="keyword">public</span> <span class="function"><span class="keyword">void</span> <span class="title">onResponse</span><span class="params">(JSONObject response)</span> </span>{
                        Log.d(TAG, response.toString());
                    }
                }, <span class="keyword">new</span> Response.ErrorListener() {
    
                    <span class="annotation">@Override</span>
                    <span class="keyword">public</span> <span class="function"><span class="keyword">void</span> <span class="title">onErrorResponse</span><span class="params">(VolleyError <span class="keyword">error</span>)</span> </span>{
                        VolleyLog.d(TAG, <span class="string">"Error: "</span> + <span class="keyword">error</span>.getMessage());
                    }
                });
    
    <span class="comment">// Adding request to request queue</span>
    AppController.getInstance().addToRequestQueue(jsonObjReq, tag_json_obj);
    

    创建String请求

    StringRequest可以用来请求任何string类型的数据:json,xml,文本等等。

    <span class="comment">// Tag used to cancel the request</span>
    String  tag_string_req = <span class="string">"string_req"</span>;
    
    String url = <span class="string">"http://api.androidhive.info/volley/string_response.html"</span>;
    
    ProgressDialog pDialog = new ProgressDialog<span class="params">(this)</span>;
    pDialog.setMessage<span class="params">(<span class="string">"Loading..."</span>)</span>;
    pDialog.show<span class="params">()</span>;     
    
    StringRequest strReq = new StringRequest<span class="params">(Method.GET,
                url, new Response.Listener<String><span class="params">()</span> {
    
                    @Override
                    public void onResponse<span class="params">(String response)</span> {
                        Log.d<span class="params">(TAG, response.toString<span class="params">()</span>)</span>;
                        pDialog.hide<span class="params">()</span>;
    
                    }
                }, new Response.ErrorListener<span class="params">()</span> {
    
                    @Override
                    public void onErrorResponse<span class="params">(VolleyError error)</span> {
                        VolleyLog.d<span class="params">(TAG, <span class="string">"Error: "</span> + error.getMessage<span class="params">()</span>)</span>;
                        pDialog.hide<span class="params">()</span>;
                    }
                })</span>;
    
    <span class="comment">// Adding request to request queue</span>
    AppController.getInstance<span class="params">()</span>.addToRequestQueue<span class="params">(strReq, tag_string_req)</span>;
    

    创建POST请求

    上面说的都是GET请求,下面来说一下POST请求,与GET请求不同的是,只要在创建请求的时候将请求类型改为POST请求,并且override Request的getParams方法即可。

    <span class="comment">// Tag used to cancel the request</span>
    <span class="built_in">String</span> tag_json_obj = <span class="string">"json_obj_req"</span>;
    
    <span class="built_in">String</span> url = <span class="string">"http://api.androidhive.info/volley/person_object.json"</span>;
    ProgressDialog pDialog = <span class="literal">new</span> ProgressDialog(this);
    pDialog<span class="built_in">.</span>setMessage(<span class="string">"Loading..."</span>);
    pDialog<span class="built_in">.</span>show();     
    
        JsonObjectRequest jsonObjReq = <span class="literal">new</span> JsonObjectRequest(Method<span class="built_in">.</span>POST,
                url, <span class="built_in">null</span>,
                <span class="literal">new</span> Response<span class="built_in">.</span>Listener<JSONObject>() {
    
                    @Override
                    <span class="keyword">public</span> <span class="literal">void</span> onResponse(JSONObject response) {
                        <span class="keyword">Log</span><span class="built_in">.</span>d(<span class="built_in">TAG</span>, response<span class="built_in">.</span>toString());
                        pDialog<span class="built_in">.</span>hide();
                    }
                }, <span class="literal">new</span> Response<span class="built_in">.</span>ErrorListener() {
    
                    @Override
                    <span class="keyword">public</span> <span class="literal">void</span> onErrorResponse(VolleyErr<span class="subst">or</span> err<span class="subst">or</span>) {
                        VolleyLog<span class="built_in">.</span>d(<span class="built_in">TAG</span>, <span class="string">"Error: "</span> + err<span class="subst">or</span><span class="built_in">.</span>getMessage());
                        pDialog<span class="built_in">.</span>hide();
                    }
                }) {
    
            @Override
            <span class="keyword">protected</span> <span class="built_in">Map</span><<span class="built_in">String</span>, <span class="built_in">String</span>> getParams() {
                <span class="built_in">Map</span><<span class="built_in">String</span>, <span class="built_in">String</span>> <span class="keyword">params</span> = <span class="literal">new</span> HashMap<<span class="built_in">String</span>, <span class="built_in">String</span>>();
                <span class="keyword">params</span><span class="built_in">.</span>put(<span class="string">"name"</span>, <span class="string">"Androidhive"</span>);
                <span class="keyword">params</span><span class="built_in">.</span>put(<span class="string">"email"</span>, <span class="string">"abc@androidhive.info"</span>);
                <span class="keyword">params</span><span class="built_in">.</span>put(<span class="string">"password"</span>, <span class="string">"password123"</span>);
    
                <span class="keyword">return</span> <span class="keyword">params</span>;
            }
    
        };
    
    <span class="comment">// Adding request to request queue</span>
    AppController<span class="built_in">.</span>getInstance()<span class="built_in">.</span>addToRequestQueue(jsonObjReq, tag_json_obj);
    

    ##添加请求头部信息

    <span class="comment">// Tag used to cancel the request</span>
    <span class="keyword">String</span> tag_json_obj = <span class="string">"json_obj_req"</span>;
    
    <span class="keyword">String</span> url = <span class="string">"http://api.androidhive.info/volley/person_object.json"</span>;
    
    ProgressDialog pDialog = <span class="keyword">new</span> ProgressDialog(<span class="keyword">this</span>);
    pDialog.setMessage(<span class="string">"Loading..."</span>);
    pDialog.show();     
    
    JsonObjectRequest jsonObjReq = <span class="keyword">new</span> JsonObjectRequest(Method.POST,url, <span class="keyword">null</span>,<span class="keyword">new</span> Response.Listener<<span class="keyword">JSONObject</span>>() {
        @Override
        <span class="keyword">public</span> <span class="keyword">void</span> onResponse(<span class="keyword">JSONObject</span> response) {
            Log.d(TAG, response.toString());
            pDialog.hide();
        }
    }, <span class="keyword">new</span> Response.ErrorListener() {
        @Override
        <span class="keyword">public</span> <span class="keyword">void</span> onErrorResponse(VolleyError error) {
            VolleyLog.d(TAG, <span class="string">"Error: "</span> + error.getMessage());
            pDialog.hide();
        }
    }) {
    
    <span class="comment">/**
    * Passing some request headers
    * */</span>
    @Override
    <span class="keyword">public</span> Map<<span class="keyword">String</span>, <span class="keyword">String</span>> getHeaders() <span class="keyword">throws</span> AuthFailureError {
        <span class="keyword">HashMap</span><<span class="keyword">String</span>, <span class="keyword">String</span>> headers = <span class="keyword">new</span> <span class="keyword">HashMap</span><<span class="keyword">String</span>, <span class="keyword">String</span>>();
        headers.put(<span class="string">"Content-Type"</span>, <span class="string">"application/json"</span>);
        headers.put(<span class="string">"apiKey"</span>, <span class="string">"xxxxxxxxxxxxxxx"</span>);
        <span class="keyword">return</span> headers;
    }
    };
    <span class="comment">// Adding request to request queue</span>
    AppController.getInstance().addToRequestQueue(jsonObjReq, tag_json_obj);
    

    ##创建Image请求
    Volley库中自带了NetworkImageView类,这个ImageView可以自动使用volley下载图片

    ###用NetworkImageView加载图片
    首先,说明一下,加载图片的原理:

    NetworkImageView加载图片需要一个ImageLoader和一个图片URL,这个ImageLoader对象需要一个请求队列对象和ImageCahe对象。调用NetworkImageView的setUrl方法后,首先会判断当前ImageView的URL和新传入的URL是否一致,如果相同,就不用再发送http请求了,如果不同,那么就使用ImageLoader对象来发送http请求获取图片。

    ImageLoader imageLoader = AppController.getInstance<span class="params">()</span>.getImageLoader<span class="params">()</span>;
    <span class="comment">// If you are using NetworkImageView</span>
    imgNetWorkView.setImageUrl<span class="params">(Const.URL_IMAGE, imageLoader)</span>;
    

    加载一个图片只要这么简单~~~

    ###用ImageView来加载图片
    这个过程和NetworkImageView类似

    ImageLoader imageLoader = AppController.getInstance().getImageLoader();
    
    <span class="comment">// If you are using normal ImageView</span>
    imageLoader.get(Const.URL_IMAGE, <span class="keyword">new</span> ImageListener() {
    
        <span class="annotation">@Override</span>
        <span class="keyword">public</span> <span class="function"><span class="keyword">void</span> <span class="title">onErrorResponse</span><span class="params">(VolleyError <span class="keyword">error</span>)</span> </span>{
            Log.e(TAG, <span class="string">"Image Load Error: "</span> + <span class="keyword">error</span>.getMessage());
        }
    
        <span class="annotation">@Override</span>
        <span class="keyword">public</span> <span class="function"><span class="keyword">void</span> <span class="title">onResponse</span><span class="params">(ImageContainer response, <span class="keyword">boolean</span> arg1)</span> </span>{
            <span class="keyword">if</span> (response.getBitmap() != <span class="keyword">null</span>) {
                <span class="comment">// load image into imageview</span>
                imageView.setImageBitmap(response.getBitmap());
            }
        }
    });
    

    可以再简单一点:

    // Loading image <span class="keyword">with</span> placeholder <span class="literal">and</span> error image
    imageLoader.get(<span class="keyword">Const</span>.URL_IMAGE, ImageLoader.getImageListener(imageView, R.drawable.ico_loading, R.drawable.ico_error))<span class="comment">;</span>
    

    ImageLoader.getImageListener方法中已经写了一个默认的ImageListener

    ##Volley Cache
    volley中自带了强大的cache机制来管理请求cache,这会减少网络请求次数和用户等待时间。

    ###从请求Cache中加载请求

    <span class="keyword">Cache</span> <span class="keyword">cache</span> = AppController<span class="built_in">.</span>getInstance()<span class="built_in">.</span>getRequestQueue()<span class="built_in">.</span>getCache();
    Entry entry = <span class="keyword">cache</span><span class="built_in">.</span>get(url);
    <span class="keyword">if</span>(entry != <span class="built_in">null</span>){
        try {
            <span class="built_in">String</span> <span class="built_in">data</span> = <span class="literal">new</span> <span class="built_in">String</span>(entry<span class="built_in">.</span><span class="built_in">data</span>, <span class="string">"UTF-8"</span>);
            <span class="comment">// handle data, like converting it to xml, json, bitmap etc.,</span>
        } catch (UnsupportedEncodingException e) {      
            e<span class="built_in">.</span>printStackTrace();
            }
        }
    }<span class="keyword">else</span>{
        <span class="comment">// Cached response doesn't exists. Make network call here</span>
    }
    

    ###使请求缓存失效
    失效并不意味这删除,Volley还会继续使用缓存的对象直到从服务器上获取到了新的数据,新的数据会覆盖旧的数据。

    AppController.getInstance<span class="params">()</span>.getRequestQueue<span class="params">()</span>.getCache<span class="params">()</span>.invalidate<span class="params">(url, <span class="literal">true</span>)</span>;
    

    ###关闭Cache
    如果你想将某一个请求的Cache功能关闭,直接调用Request的setShouldCache()方法就可以:

    <span class="comment">// String request</span>
    StringRequest stringReq = <span class="literal">new</span> StringRequest(<span class="attribute">...</span><span class="built_in">.</span>);
    
    <span class="comment">// disable cache</span>
    stringReq<span class="built_in">.</span>setShouldCache(<span class="literal">false</span>);
    

    ###将某一URL的Cache删除
    调用Cacheremove方法可以删除这个URL的cache:

    <span class="tag">AppController</span><span class="class">.getInstance</span>()<span class="class">.getRequestQueue</span>()<span class="class">.getCache</span>()<span class="class">.remove</span>(<span class="tag">url</span>);
    

    ###删除所有的Cache

    <span class="tag">AppController</span><span class="class">.getInstance</span>()<span class="class">.getRequestQueue</span>()<span class="class">.getCache</span>()<span class="class">.clear</span>();
    

    ##取消请求
    在你添加一个请求到请求队列中的时候,你可以发现,addToRequestQueue(request, tag)方法还接受一个tag参数,这个tag就是用来标记某一类请求的,这样就可以取消这个tag的所有请求了:

    String tag_json_arry = <span class="string">"json_req"</span>;
    ApplicationController.getInstance<span class="params">()</span>.getRequestQueue<span class="params">()</span>.cancelAll<span class="params">(<span class="string">"feed_request"</span>)</span>;
    

    ##请求优先级
    在创建一个request的时候可以Override Request方法的getPriority方法返回一个优先级,优先级分为:Normal, Low, Immediate, High

    <span class="keyword">private</span> Priority priority = Priority.HIGH;
    
    StringRequest strReq = <span class="keyword">new</span> StringRequest(Method.<span class="keyword">GET</span>,
                <span class="keyword">Const</span>.URL_STRING_REQ, <span class="keyword">new</span> <span class="built_in">Response</span>.Listener<<span class="built_in">String</span>>() {
    
                    @Override
                    <span class="keyword">public</span> void onResponse(<span class="built_in">String</span> <span class="built_in">response</span>) {
                        <span class="built_in">Log</span>.d(TAG, <span class="built_in">response</span>.toString());
                        msgResponse.setText(<span class="built_in">response</span>.toString());
                        hideProgressDialog();
    
                    }
                }, <span class="keyword">new</span> <span class="built_in">Response</span>.ErrorListener() {
    
                    @Override
                    <span class="keyword">public</span> void onErrorResponse(VolleyError <span class="keyword">error</span>) {
                        VolleyLog.d(TAG, <span class="string">"Error: "</span> + <span class="keyword">error</span>.getMessage());
                        hideProgressDialog();
                    }
                }) {
            @Override
            <span class="keyword">public</span> Priority getPriority() {
                return priority;
            }
    
        };
    

    ##Missing! 创建xml请求
    就像创建Gson请求一样,你可以自定义一个XMLRequest类来请求xml数据