如何使用Volley?

作者: Jaesoon | 来源:发表于2018-07-13 16:13 被阅读33次

    如何使用Volley?

    引用

    使用之前,希望你看过之前的文档,知道Volley适合干啥?简单点说,就是小且高并发的请求适合使用Volley。我们App一般的接口请求具有上面的特点,所以适合使用。接下来,我们举三个栗子,来了解如何使用。

    发送一个简单请求

    从上层使用上来讲,我们通过创建一个RequestQueue,然后传递给它一个Reques对象来使用Volley。RequestQueue对象管理运行网络操作的工作线程,读取和写入缓存,和解析响应内容。Requests处理解析原始响应内容,然后,Volley照顾派发解析后的结果到主线程用于传送。
    这段内容,我们先使用简单的方法-Volley.newRequestQueue创建一个请求。

    1. 添加网络请求权限

    额,比较简单,所有涉及到网络请求的应用都需要在AndroidManifest.xml中申请网络权限。代码简单,直接添加就行了。

        <uses-permission android:name="android.permission.INTERNET" />
    

    2. 使用Volley.newRequestQueue方法

    我们使用这个方法来创建一个RequestQueue,不做任何请求配置,直接使用默认的配置。

    final TextView mTextView = (TextView) findViewById(R.id.text);
    // ...
    
    // Instantiate the RequestQueue.
    RequestQueue queue = Volley.newRequestQueue(this);
    String url ="http://www.baidu.com";
    
    // Request a string response from the provided URL.
    StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
                new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            // Display the first 500 characters of the response string.
            // mTextView.setText("Response is: "+ response.substring(0,500));
            Log.e("VolleyTest","Response is: "+ response.substring(0,500));
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            // mTextView.setText("That didn't work!");
            Log.e("VolleyTest","Bad lucy,it didn't work!");
        }
    });
    
    // Add the request to the RequestQueue.
    queue.add(stringRequest);
    

    细心的你,应该已经注意到了,我们在初始化时,传入了当前Activity的context。

    RequestQueue queue = Volley.newRequestQueue(this);
    

    然后,我们创建了一个StringRequest。它是Request的子类。上面说过,我们的Request负责解析返回的内容,然后将解析后的对象给Volley,然后Volley将解析后得到的对象派发到主线程。StringRequst的构造函数,让我们传入四个参数,分别是:请求的方法类型,目标url,一个成功回调,和一个报错回调。我们在成功回调中拿到想要的数据,在失败回调中拿到失败的原因。需要我们注意的是:Volley将结果传递到主线程了,所以,我们能在回调中进行UI填充。这一点很爽啊,像OKhttp就不默认支持。如果要用的话,我们需要封装一下。Comes out of the box,哈哈,开箱即用。

    3. 添加一个请求

    你可以向上面那样,直接调用add()方法,将请求添加到RequestQueue。一旦你添加了它,它将移入流水线(pineline),获得服务,得到的原始响应数据被解析和传送到主线程(调用你设置好的回调)。
    当你调用add()后,Volley将运行一个缓存处理线程和一个网络线程派发线程池。当你添加了一个请求到队列,它将被缓存线程选中,然后进行鉴别:

    • 如果缓存能够为它提供服务,缓存过的响应内容在缓存处理线程解析,然后将解析后的对象传送到主线程。
    • 如果不能,它将被放置到网路线程。第一个空闲的线程,将这个请求从队列中取出,执行HTTP事务,在工作线程解析原始结果。然后,将原始结果加入缓存。同时,将解析后的对象,递送到主线程来传递。

    需要注意的是,阻塞I/O和解析/解码等耗时的操作是在工作线程上完成的。你可以从任何线程添加请求,但响应始终在主线程上传递。


    纸上得来终觉浅,绝知此时要有图

    4. 取消请求

    阴阳相生,凡事有阴必有阳。有请求,总会有取消请求的需要。也许你现在不需要,总有一天你会需要。如何取消一个请求?只需要调用Request的cancle()方法即可。调用这个方法之后,Volley保证不会回调你设置的回调。哈哈,妈妈再也不用担心我的程序leakwindow了呢。
    然鹅,你肯定会问,如果我要取消当前Activity或Fragment的所有的请求呢?难道一个一个去取消?那不要累死人啦。当然不是啦,我们也可以调用RequestQueue的cancelAll()方法,取消所有请求。额,对了,有两个重载方法分别是:

    • public void cancelAll(final Object tag)
    • public void cancelAll(RequestFilter filter)
      所以,你可以给你的Request设置一个Tag或者filter,然后取消指定的分类。
    1. 给你的请求设置Tag
    public static final String TAG = "MyTag";
    StringRequest stringRequest; // Assume this exists.
    RequestQueue mRequestQueue;  // Assume this exists.
    
    // Set the tag on the request.
    stringRequest.setTag(TAG);
    
    // Add the request to the RequestQueue.
    mRequestQueue.add(stringRequest);
    
    1. 取消你的请求
    @Override
    protected void onStop () {
        super.onStop();
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(TAG);
        }
    }
    

    需要注意的是,你不要随便的取消请求,特别是,你下一步的操作,一定需要请求到的数据。额,啰嗦。

    创建一个RequestQueue

    前面一个章节,我们使用Volley.newRequestQueue()方法创建了一个RequestQueue,Volley默认为我们设置好了一些配置。这一节,我们来个性化定制一下。
    同时,这一节,我们还讲一下如何单例一个RequestQueue。

    1. 设置网络和缓存

    RequestQueue需要两件来完成它的工作:网络用来传输请求;缓存来处理完成缓存。在Volley的工具箱中有一些已经按照标准实现的类:DiskBasedCash提供一个内存索引的每一个请求一个文件的缓存;BaseNetwork基于你首选的HTTP客户端来提供网络传输。
    BaseNetwork是volley默认的网络实现。BaseNetwork必须和HTTP客户端一起初始化,HTTP客户端是你的Appy用来连接网络。典型的,它是HttpURLConnection。
    接下来的代码,展示如何创建和设置RequestQueue。

    RequestQueue mRequestQueue;
    
    // Instantiate the cache
    Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap
    
    // Set up the network to use HttpURLConnection as the HTTP client.
    Network network = new BasicNetwork(new HurlStack());
    
    // Instantiate the RequestQueue with the cache and network.
    mRequestQueue = new RequestQueue(cache, network);
    
    // Start the queue
    mRequestQueue.start();
    
    String url ="http://www.example.com";
    
    // Formulate the request and handle the response.
    StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            // Do something with the response
        }
    },
        new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // Handle error
        }
    });
    
    // Add the request to the RequestQueue.
    mRequestQueue.add(stringRequest);
    
    // ...
    

    如果你只需要一次请求,不想保留线程池,你可以在任何需要的地方创建RequestQueue,在得到数据或者失败回调之后,调用stop()方法。但是更常见的一个场景是,你需要创建一个单例的在整个App的生命周期中运行的RequestQueue。

    2. 使用单例模式

    如果你的应用程序不断使用网络,那么设置RequestQueue的单个实例可能是最有效的,该实例将持续你的应用程序的生命周期。你可以通过各种方式来实现这一目标。推荐的方式是实现一个单例的封装了RequestQueue和其它Volley功能的类。另外一种方式是在Application的子类的onCreate方法中设置RequestQueue。但是不鼓励使用这种方式;静态单例可以以更模块化的方式提供相同的功能。
    一个关键的概念是:RequestQueue必须以Application而不是Activity的context初始化。这可确保RequestQueue将持续应用程序的生命周期,而不是每次重新创建Activity时重新创建(例如,当用户旋转设备时)。
    下面举个例子:

    public class MySingleton {
        private static MySingleton mInstance;
        private RequestQueue mRequestQueue;
        private ImageLoader mImageLoader;
        private static Context mCtx;
    
        private MySingleton(Context context) {
            mCtx = context;
            mRequestQueue = getRequestQueue();
    
            mImageLoader = new ImageLoader(mRequestQueue,
                    new ImageLoader.ImageCache() {
                private final LruCache<String, Bitmap>
                        cache = new LruCache<String, Bitmap>(20);
    
                @Override
                public Bitmap getBitmap(String url) {
                    return cache.get(url);
                }
    
                @Override
                public void putBitmap(String url, Bitmap bitmap) {
                    cache.put(url, bitmap);
                }
            });
        }
    
        public static synchronized MySingleton getInstance(Context context) {
            if (mInstance == null) {
                mInstance = new MySingleton(context);
            }
            return mInstance;
        }
    
        public RequestQueue getRequestQueue() {
            if (mRequestQueue == null) {
                // getApplicationContext() is key, it keeps you from leaking the
                // Activity or BroadcastReceiver if someone passes one in.
                mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
            }
            return mRequestQueue;
        }
    
        public <T> void addToRequestQueue(Request<T> req) {
            getRequestQueue().add(req);
        }
    
        public ImageLoader getImageLoader() {
            return mImageLoader;
        }
    }
    

    如何使用这个单例?

    // Get a RequestQueue
    RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).
        getRequestQueue();
    
    // ...
    
    // Add a request (in this example, called stringRequest) to your RequestQueue.
    MySingleton.getInstance(this).addToRequestQueue(stringRequest);
    

    创建一个标准请求

    Volley默认支持的请求结果:

    • StringRequest 指定一个URL,获取到字符串数据。
    • JsonObjectRequest 指定URL,获取到一个JsonObject
    • JsonArrayRequest 同上获取到JsonArray
      如果你恰好需要以上几种结果,那么,你直接使用标准的请求即可,而不是去实现一个自己个性化定制的Request。比较简单,直接给出代码。
    String url = "http://my-json-feed";
    
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
            (Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
    
        @Override
        public void onResponse(JSONObject response) {
            mTextView.setText("Response: " + response.toString());
        }
    }, new Response.ErrorListener() {
    
        @Override
        public void onErrorResponse(VolleyError error) {
            // TODO: Handle error
    
        }
    });
    
    // Access the RequestQueue through your singleton class.
    MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);
    

    创建一个自定义的请求

    如果标准请求不符合你想要的结果,你也可以自己创建一个个性化的请求。

    1. 写一个自定义的请求

    要写一个自定义的请求,你必须按照下面的做:

    • 继承Request<T>类,<T>表示你的请求解析后想要得到的对象。这就是说,如果你想要的结果是String,创建自定义请求通过继承Request<String>。查看Volley默认支持的请求类型StringRequest和ImageRequest的代码作为示例。
    • 实现抽象方法parseNetworkResponse()和deliverResponse(),详细信息如下:
    parseNetworkResponse

    Respouse封装了一个解析后的会被传递的给定类型的对象,例如:字符串、图片或者JSON。这有一个parseNetworkRewponse方法的代码。

    @Override
    protected Response<T> parseNetworkResponse(
            NetworkResponse response) {
        try {
            String json = new String(response.data,
            HttpHeaderParser.parseCharset(response.headers));
        return Response.success(gson.fromJson(json, clazz),
        HttpHeaderParser.parseCacheHeaders(response));
        }
        // handle errors
    // ...
    }
    

    注意:

    • parseNetworkResponse() takes as its parameter a NetworkResponse, which contains the response payload as a byte[], HTTP status code, and response headers. parseNetworkResponse()将NetworkResponse作为它的参数,NetworkResponse包含了响应负载(作为bype[]),HTTP状态码,和响应的报文头。
    • 你的实现必须返回Response<T>,其中包含了你定义的响应类型对象,和缓存的元数据或者错误,比如,在解析失败的情况下。

    如果你的协议有非标准的缓存语义,你可以自己构建一个Cache.Entry,但大多数请求都可以这样:

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

    Volley从工作线程调用parseNetworkResponse()。这确保了昂贵的解析操作(例如将JPEG解码为Bitmap)不会阻止UI线程。

    deliverResponse

    Volley使用你在parseNetworkResponse()中返回的对象调用主线程。大多数请求在此处调用回调接口,例如:

    protected void deliverResponse(T response) {
            listener.onResponse(response);
    }
    

    2. 示例:GsonRequest

    Gson是一个使用反射将Java对象转换成字JSON串或将JSON串转换成Java对象的工具库。(Gson is a library for converting Java objects to and from JSON using reflection. )
    你可以定义与其对应的JSON键具有相同名称的Java对象,将Gson传递给类对象,Gson将为你填写字段。

    public class GsonRequest<T> extends Request<T> {
        private final Gson gson = new Gson();
        private final Class<T> clazz;
        private final Map<String, String> headers;
        private final Listener<T> listener;
    
        /**
         * Make a GET request and return a parsed object from JSON.
         *
         * @param url URL of the request to make
         * @param clazz Relevant class object, for Gson's reflection
         * @param headers Map of request headers
         */
        public GsonRequest(String url, Class<T> clazz, Map<String, String> headers,
                Listener<T> listener, ErrorListener errorListener) {
            super(Method.GET, url, errorListener);
            this.clazz = clazz;
            this.headers = headers;
            this.listener = listener;
        }
    
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            return headers != null ? headers : super.getHeaders();
        }
    
        @Override
        protected void deliverResponse(T response) {
            listener.onResponse(response);
        }
    
        @Override
        protected Response<T> parseNetworkResponse(NetworkResponse response) {
            try {
                String json = new String(
                        response.data,
                        HttpHeaderParser.parseCharset(response.headers));
                return Response.success(
                        gson.fromJson(json, clazz),
                        HttpHeaderParser.parseCacheHeaders(response));
            } catch (UnsupportedEncodingException e) {
                return Response.error(new ParseError(e));
            } catch (JsonSyntaxException e) {
                return Response.error(new ParseError(e));
            }
        }
    }
    

    以上就是如何使用Volley的方法,接下来一章,我们开始分析Volley源码。

    相关文章

      网友评论

        本文标题:如何使用Volley?

        本文链接:https://www.haomeiwen.com/subject/sgqspftx.html