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="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span>() {
        <span class="keyword">super</span>.onCreate();
        mInstance = <span class="keyword">this</span>;
    }
    
    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> AppController <span class="title">getInstance</span>() {
        <span class="keyword">return</span> mInstance;
    }
    
    <span class="keyword">public</span> RequestQueue <span class="title">getRequestQueue</span>() {
        <span class="keyword">if</span> (mRequestQueue == <span class="keyword">null</span>) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }
    
        <span class="keyword">return</span> mRequestQueue;
    }
    
    <span class="keyword">public</span> ImageLoader <span class="title">getImageLoader</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="keyword">void</span> <span class="title">addToRequestQueue</span>(Request<T> req, String tag) {
        <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="keyword">void</span> <span class="title">addToRequestQueue</span>(Request<T> req) {
        req.setTag(TAG);
        getRequestQueue().add(req);
    }
    
    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">cancelPendingRequests</span>(Object tag) {
        <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="keyword">int</span> <span class="title">getDefaultLruCacheSize</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="keyword">public</span> <span class="title">LruBitmapCache</span>() {
            <span class="keyword">this</span>(getDefaultLruCacheSize());
        }
    
        <span class="keyword">public</span> <span class="title">LruBitmapCache</span>(<span class="keyword">int</span> sizeInKiloBytes) {
            <span class="keyword">super</span>(sizeInKiloBytes);
        }
    
        <span class="annotation">@Override</span>
        <span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">sizeOf</span>(String key, Bitmap value) {
            <span class="keyword">return</span> value.getRowBytes() * value.getHeight() / <span class="number">1024</span>;
        }
    
        <span class="annotation">@Override</span>
        <span class="keyword">public</span> Bitmap <span class="title">getBitmap</span>(String url) {
            <span class="keyword">return</span> get(url);
        }
    
        <span class="annotation">@Override</span>
        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">putBitmap</span>(String url, Bitmap bitmap) {
            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="keyword">void</span> <span class="title">onResponse</span>(JSONObject response) {
                        Log.d(TAG, response.toString());
                    }
                }, <span class="keyword">new</span> Response.ErrorListener() {
    
                    <span class="annotation">@Override</span>
                    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onErrorResponse</span>(VolleyError error) {
                        VolleyLog.d(TAG, <span class="string">"Error: "</span> + error.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 = <span class="keyword">new</span> ProgressDialog(<span class="keyword">this</span>);
    pDialog.setMessage(<span class="string">"Loading..."</span>);
    pDialog.show();     
    
    StringRequest strReq = <span class="keyword">new</span> StringRequest(Method.GET,
                url, <span class="keyword">new</span> Response.Listener<String>() {
    
                    <span class="annotation">@Override</span>
                    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onResponse</span>(String response) {
                        Log.d(TAG, response.toString());
                        pDialog.hide();
    
                    }
                }, <span class="keyword">new</span> Response.ErrorListener() {
    
                    <span class="annotation">@Override</span>
                    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onErrorResponse</span>(VolleyError error) {
                        VolleyLog.d(TAG, <span class="string">"Error: "</span> + error.getMessage());
                        pDialog.hide();
                    }
                });
    
    <span class="comment">// Adding request to request queue</span>
    AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
    

    创建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="subst">=</span> <span class="string">"json_obj_req"</span>;
    
    <span class="built_in">String</span> url <span class="subst">=</span> <span class="string">"http://api.androidhive.info/volley/person_object.json"</span>;
    ProgressDialog pDialog <span class="subst">=</span> <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="subst">=</span> <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<span class="subst"><</span>JSONObject<span class="subst">></span>() {
    
                    @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(VolleyError error) {
                        VolleyLog<span class="built_in">.</span>d(<span class="built_in">TAG</span>, <span class="string">"Error: "</span> <span class="subst">+</span> error<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="subst"><</span><span class="built_in">String</span>, <span class="built_in">String</span><span class="subst">></span> getParams() {
                <span class="built_in">Map</span><span class="subst"><</span><span class="built_in">String</span>, <span class="built_in">String</span><span class="subst">></span> <span class="keyword">params</span> <span class="subst">=</span> <span class="literal">new</span> HashMap<span class="subst"><</span><span class="built_in">String</span>, <span class="built_in">String</span><span class="subst">></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>
    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>;
    
    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<JSONObject>() {
        <span class="annotation">@Override</span>
        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onResponse</span>(JSONObject response) {
            Log.d(TAG, response.toString());
            pDialog.hide();
        }
    }, <span class="keyword">new</span> Response.ErrorListener() {
        <span class="annotation">@Override</span>
        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onErrorResponse</span>(VolleyError error) {
            VolleyLog.d(TAG, <span class="string">"Error: "</span> + error.getMessage());
            pDialog.hide();
        }
    }) {
    
    <span class="javadoc">/**
    * Passing some request headers
    * */</span>
    <span class="annotation">@Override</span>
    <span class="keyword">public</span> Map<String, String> <span class="title">getHeaders</span>() <span class="keyword">throws</span> AuthFailureError {
        HashMap<String, String> headers = <span class="keyword">new</span> HashMap<String, String>();
        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请求获取图片。

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

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

    用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="keyword">void</span> <span class="title">onErrorResponse</span>(VolleyError error) {
            Log.e(TAG, <span class="string">"Image Load Error: "</span> + error.getMessage());
        }
    
        <span class="annotation">@Override</span>
        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onResponse</span>(ImageContainer response, <span class="keyword">boolean</span> arg1) {
            <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 with placeholder <span class="literal">and</span> <span class="built_in">error</span> image
    imageLoader.get(<span class="keyword">Const</span>.URL_IMAGE, ImageLoader.getImageListener(imageView, R.drawable.ico_loading, R.drawable.ico_error));
    

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

    Volley Cache

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

    从请求Cache中加载请求

    <span class="keyword">Cache</span> <span class="keyword">cache</span> <span class="subst">=</span> AppController<span class="built_in">.</span>getInstance()<span class="built_in">.</span>getRequestQueue()<span class="built_in">.</span>getCache();
    Entry entry <span class="subst">=</span> <span class="keyword">cache</span><span class="built_in">.</span>get(url);
    <span class="keyword">if</span>(entry <span class="subst">!=</span> <span class="built_in">null</span>){
        try {
            <span class="built_in">String</span> <span class="built_in">data</span> <span class="subst">=</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().getRequestQueue().getCache().invalidate(url, <span class="literal">true</span>);
    

    关闭Cache

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

    <span class="comment">// String request</span>
    StringRequest stringReq <span class="subst">=</span> <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:

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

    删除所有的Cache

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

    取消请求

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

    <span class="built_in">String</span> tag_json_arry = <span class="string">"json_req"</span>;
    ApplicationController.getInstance().getRequestQueue().cancelAll(<span class="string">"feed_request"</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.GET,
                Const.URL_STRING_REQ, <span class="keyword">new</span> Response.Listener<String>() {
    
                    <span class="annotation">@Override</span>
                    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onResponse</span>(String response) {
                        Log.d(TAG, response.toString());
                        msgResponse.setText(response.toString());
                        hideProgressDialog();
    
                    }
                }, <span class="keyword">new</span> Response.ErrorListener() {
    
                    <span class="annotation">@Override</span>
                    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onErrorResponse</span>(VolleyError error) {
                        VolleyLog.d(TAG, <span class="string">"Error: "</span> + error.getMessage());
                        hideProgressDialog();
                    }
                }) {
            <span class="annotation">@Override</span>
            <span class="keyword">public</span> Priority <span class="title">getPriority</span>() {
                <span class="keyword">return</span> priority;
            }
    
        };
    

    Missing! 创建xml请求 {#Missing!_创建xml请求}

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