Volley使用介绍

Quibbler 2021-2-2 594

Volley使用介绍


        安卓开发要对几个网络开源库非常熟悉:OkHttpVolleyRetrofit。先从轻量级的网络请求库Volley学习,它的源码不到1万行,麻雀虽小五脏俱全。



1、Volley介绍

        Volley是Google官方2013年发布的Android平台的网络通信库。该开源框架目前看来已经非常稳定,大部分代码提交记录定格在3年前(不是没人维护了,而是不需要再修改)

        GitHub:google/volley


1.1、特点

        可以访问普通的网络数据、或者Json数据、再或者下载图片。这写都是Android开发中最常见的网络请求场景,使用Volley可以提高项目的开发效率,降低重复工作,这么好的轮子不用?

        此外,Volley还可以对请求队列进行排序,取消,缓存等。


1.2、适用场景

        Volley适合进行数据量不大但是通信频繁的网络操作,比如评论、点赞等场景。

        但对于数据量比较大的网络操作其性能表现就比较差,不宜用Volley下载文件操作、短视频缓存。此时应该选用其它合适的网络库或者开发者用原生的HttpURLConnection实现。



2、引入Volley

        在项目的build.gradle中添加下面Volley依赖,最新稳定版本是1.1.1,很久没有更新了。参考Android 开发者 > 文档 > 指南 > Volley 概览

    dependencies {
        ...
        implementation 'com.android.volley:volley:1.1.1'
    }

        使用Volley别忘了在AndroidManifest.xml中添加android.permission.INTERNET网络权限

    <!--网络权限-->
    <uses-permission android:name="android.permission.INTERNET" />



3、请求回调Listener

        每个请求都需要一个结果返回监听器Listener<T>和者错误监听器ErrorListener,它们都是定义在Response<T>中的接口。在请求返回后在主线程中回调Listener<T>的onResponse(T response)方法,当请求失败出错,则回调ErrorListeneronErrorResponse(VolleyError error)方法。

    /** Callback interface for delivering parsed responses. */
    public interface Listener<T> {
        /** Called when a response is received. */
        void onResponse(T response);
    }
    
    /** Callback interface for delivering error responses. */
    public interface ErrorListener {
        /**
         * Callback method that an error has been occurred with the provided error code and optional
         * user-readable message.
         */
        void onErrorResponse(VolleyError error);
    }



4、请求示例

        Volley将网络请求抽象为Request<T>,内部有三个实现类:StringRequestJsonRequestImageRequest。用Kotlin分别简单演示一下Volley请求网络数据、Json数据、加载图片。参考Android 开发者 > 文档 > 指南 > 提出标准请求

        源码流程以后再研究。


4.1、StringRequest

        先构造一个StringRequest文本请求,有两个构造函数:

    public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
        super(method, url, errorListener);
        mListener = listener;
    }
    
    public StringRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
        this(Request.Method.GET, url, listener, errorListener);
    }

        构造好StringRequest之后将其添加到Volley请求队列中。

    private fun stringRequest() {
        val url: String = "https://www.baidu.com"
        
        val stringRequest: StringRequest = StringRequest(Request.Method.GET, url,
                {
                    //callback in main thread
                    textView.text = it.toString()
                    Log.d(TAG, it.toString())
                },
                {
                    Log.e(TAG, it.message.toString())
                })
                
        Volley.newRequestQueue(this).add(stringRequest)
    }


4.2、JsonRequest(JsonObjectRequest 和 JsonArrayRequest)

        JsonRequest已经被废弃,取而代之的是两个子类JsonObjectRequestJsonArrayRequest。分别用来解析Json对象和Json数组。

        JsonArrayRequest的构造方法参数如下

    public JsonArrayRequest(String url, Listener<JSONArray> listener, ErrorListener errorListener) {
        super(Method.GET, url, null, listener, errorListener);
    }
    
    public JsonArrayRequest(int method, String url, JSONArray jsonRequest,
                            Listener<JSONArray> listener, ErrorListener errorListener) {
        super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener, errorListener);
    }

        JsonObjectRequest的构造方法参数如下

    public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
                             Listener<JSONObject> listener, ErrorListener errorListener) {
        super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener, errorListener);
    }
    
    public JsonObjectRequest(String url, JSONObject jsonRequest,
                             Listener<JSONObject> listener, ErrorListener errorListener) {
        this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest, listener, errorListener);
    }

        构造好JsonRequest之后将其添加到Volley请求队列中。

    private fun jsonRequest() {
        val url: String = "http://quibbler.cn:3000/search?keywords=海阔天空"
        
        val jsonRequest: JsonObjectRequest = JsonObjectRequest(Request.Method.GET,
                url,
                null,
                {
                    //JSONObject
                    textView.text = it.toString()
                },
                {
                    Log.d(TAG, it?.message.toString())
                })
                
        VolleyInstance.addToRequestQueue(jsonRequest)
    }


4.3、ImageRequest

        构造ImageRequest的参数比较多,也是合情合理,熟悉网络图片加载的开发应该对这些参数比较熟悉。关于Bitmap见Bitmap位图介绍

    /**
     * @param url           图片地址
     * @param listener      请求响应成功回调
     * @param maxWidth      图片最大宽度
     * @param maxHeight     图片最大高度
     * @param scaleType     ImageViews ScaleType用于计算所需的图像大小。
     * @param decodeConfig  图片的颜色属性,其值是Bitmap.Config类的几个常量
     * @param errorListener 请求响应失败回调
     */
    public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,
                        ImageView.ScaleType scaleType, Bitmap.Config decodeConfig, Response.ErrorListener errorListener) {
        super(Request.Method.GET, url, errorListener);
        ...
    }

        构造好ImageRequest之后将其添加到Volley请求队列中加载图片,网络图片加载完成回调中可以直接设置给ImageView控件。

    private fun imageRequest() {
        val url: String = "http://quibbler.cn/upload/forum/10.png"
        
        val imageRequest: ImageRequest = ImageRequest(url,
                {
                    //Bitmap
                    imageView.setImageBitmap(it)
                },
                200, 200,
                ImageView.ScaleType.FIT_CENTER,
                Bitmap.Config.ALPHA_8,
                {
                    Log.d(TAG, it?.message.toString())
                })
        imageRequest.setShouldCache(true).setTag(TAG)
        
        VolleyInstance.addToRequestQueue(imageRequest)
    }



5、最佳单例Volley

        得益于Kotlin的语法层面支持,可以完美的实现一个Volley单例,整个应用全局可以获取RequestQueue进行请求,这样的单例是最高效的。而且应该通过全局Application Context初始化,而不是Activity的Context,获取应用全局Context方法见如何获取全局Context?。参考Android 开发者 > 文档 > 指南 > 使用单例模式

    import android.graphics.Bitmap
    import android.util.LruCache
    import com.android.volley.Request
    import com.android.volley.RequestQueue
    import com.android.volley.toolbox.ImageLoader
    import com.android.volley.toolbox.Volley
    
    object VolleyInstance {
    
        private val requestQueue: RequestQueue = Volley.newRequestQueue(MyApplication.getApplication())
        
        private val imageLoader: ImageLoader = ImageLoader(requestQueue,
                object : ImageLoader.ImageCache {
                    val cache = LruCache<String, Bitmap>(20)
                    override fun getBitmap(url: String): Bitmap {
                        return cache.get(url)
                    }
                    override fun putBitmap(url: String, bitmap: Bitmap) {
                        cache.put(url, bitmap)
                    }
                }
        )
        
        fun <T> addToRequestQueue(request: Request<T>) {
            requestQueue.add(request)
        }
        
        fun cancelRequest(tag: String?) {
            requestQueue.cancelAll(tag)
        }
        
        fun getRequestQueue(): RequestQueue {
            return requestQueue
        }
        
        fun getImageLoader(): ImageLoader {
            return imageLoader
        }
        
    }

        使用Java开发的项目单例模式详见单例的五种方式



参考资料:

        google/volley

        Android 开发者 > 文档 > 指南 > Volley 概览

        Android 开发者 > 文档 > 指南 > 发送简单请求

        Android 开发者 > 文档 > 指南 > 设置 RequestQueue

        Android 开发者 > 文档 > 指南 > 提出标准请求

        Android 开发者 > 文档 > 指南 > 实现自定义请求

        

不忘初心的阿甘
最新回复 (0)
    • 安卓笔记本
      2
        登录 注册 QQ
返回
仅供学习交流,切勿用于商业用途。如有错误欢迎指出:fluent0418@gmail.com