zoukankan      html  css  js  c++  java
  • Android网络请求通信之Volley

    一、Volley简介

    Volley网络框架是Google公司在2013年发布的一款Android平台上的网络请求通信库。以下是对Volley的简单归纳。

    Volley的优点

    1. 使网络通信更快、更简单、更健壮,用Volley开发的话,开发效率会得到很大提升,开发出来的网络模块的稳定性也会非常高
    2. Get、Post网络请求及网络图像的高效率异步处理请求,Volley帮我们实现了网络请求的异步化,而且它的Get和Post请求也是非常高效的
    3. 对网络请求进行排序、优先级处理
    4. 网络请求的缓存,当网络比较缓慢时或网络情况不太好的时候,Volley可以将我们上次请求的数据进行简单的缓存,提高用户体验
    5. Volley具有多级别取消请求,当我们有多个请求在同时进行的时候,可以做到同时取消这些请求的操作,非常的方便
    6. 和Activity生命周期的联动,当Activity结束、销毁的时候,可以同时取消网络请求的操作,避免APP在后台继续进行网络请求操作,导致APP性能和用户体验都非常差

    Volley的缺点

      Volley不适合文件的上传和下载,当我们有上传和下载的需求的时候,可以考虑其他框架

    为什么要使用Volley:

    1. 有高效的Get/Post方式的数据请求交互(效率非常高)
    2. 网络图片的加载和缓存(不使用Volley的情况下进行网络图片的处理会非常的麻烦,而且非常容易造成内存溢出,如果使用Volley,可以自动为图片进行缓存,不但节省流量,而且提高APP的性能)
    3. 是Google官方推出的针对Android平台的专用的网络通信库,Google的团队网络请求这部分优化的是非常好的,非常权威
    4. 性能很稳定,效率很强劲

    使用Volley从服务器端获取数据的几种方式

    1. StringRequest:对请求返回的数据类型不确定的情况下使用,涵盖了后面的两种请求对象
    2. JsonObjectRequest:确定请求返回的数据类型是JsonObject时使用,解析效率比StringRequest高一些
    3. JsonArrayRequest:确定求求返回的数据类型是JsonArray时使用

    本帖解决的有关Volley的五个问题

    1. Volley的Get和Post请求方式的使用
    2. Volley的网络请求队列的建立和取消队列请求
    3. Volley与Activity生命周期的联动 
    4. Volley的简单二次封装
    5. Volley获取网络图片

    二、Volley的网络请求队列的建立和取消队列请求

      我们可以建立一个全局的请求队列,再在需要的时候建立一个请求,并将这个请求加入到请求队列中,这样一来整个APP的请求都可以通过这个队列来管理。因为Volley有全局请求队列这一功能,所以Volley更适合于并发的、对效率和性能要求非常好的场景。我们需要建立一个请求队列所在的全局类(继承自Application类),代码如下:

     1 public class MyApplication extends Application {
     2     private static RequestQueue queue; // Volley的全局请求队列
     3 
     4     @Override
     5     public void onCreate() {
     6         super.onCreate();
     7         // 创建Application的同时初始化Volley全局请求队列
     8         queue = Volley.newRequestQueue(getApplicationContext());
     9     }
    10 
    11     // 静态方法返回Volley全局请求队列
    12     public static RequestQueue getRequestQueue() {
    13         return queue;
    14     }
    15 }
    请求队列所在的全局类MyApplication

      因为涉及到Application的关系,所以我们需要在AndroidMenifest文件的<application>标签中添加application的引用: android:name=".com.tools.MyApplication" 。另外,因为使用Volley需要使用网络,所以我们还需要为项目添加网络权限: <uses-permission android:name="android.permission.INTERNET" /> 。下面贴出AndroidMenifest文件中的所有代码:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     3     package="com.activity.volleyclient">
     4 
     5     <uses-permission android:name="android.permission.INTERNET" />
     6 
     7     <application
     8         android:name=".com.tools.MyApplication"
     9         android:allowBackup="true"
    10         android:icon="@mipmap/ic_launcher"
    11         android:label="@string/app_name"
    12         android:supportsRtl="true"
    13         android:theme="@android:style/Theme.NoTitleBar">
    14         <activity
    15             android:name=".MainActivity"
    16             android:label="@string/app_name"
    17             android:theme="@android:style/Theme.NoTitleBar">
    18             <intent-filter>
    19                 <action android:name="android.intent.action.MAIN" />
    20 
    21                 <category android:name="android.intent.category.LAUNCHER" />
    22             </intent-filter>
    23         </activity>
    24     </application>
    25 
    26 </manifest>
    AndroidMenifest文件中的代码

      到此为止,我们就已经创建好了请求队列。我们通过 MyApplication.getRequestQueue().add(stringRequestGet); 来向请求队列中添加请求(注意在添加之前必须为每个请求设置TAG标记,以便删除);用 MyApplication.getRequestQueue().cancelAll("tag"); 来删除请求队列中的请求。 

    三、Volley的GET和POST请求方式的使用

      上面提到过,Volley获取服务端代码有三种方式:StringRequest、JsonObjectRequest和JsonArrayRequest。由于这三种方式的代码基本一样,而且后两种相比于第一种也有一定的局限性,所以这里就以StringRequest为例,贴出程序源码和结果。

     1 public class MainActivity extends Activity {
     2     // 基本的URL地址(GET和POST都用到这个地址,只不过GET需要在URL上添加参数,而POST不需要)
     3     private static final String BASE_URL = "http://192.168.1.102:8080/VolleyServer/JsonServlet";
     4     private TextView result;
     5 
     6     @Override
     7     protected void onCreate(Bundle savedInstanceState) {
     8         super.onCreate(savedInstanceState);
     9         setContentView(R.layout.content_main);
    10         result = (TextView) findViewById(R.id.result);
    11 
    12         volleyGet();
    13         volleyPost();
    14     }
    15 
    16     // 使用GET方式从服务端获取到JSON数据并加以解析
    17     private void volleyGet() {
    18         // 使用StringRequest获取JSON数据
    19         String url = BASE_URL + "?key=person";
    20         StringRequest stringRequestGet = new StringRequest(Method.GET, url, new Response.Listener<String>() {
    21             @Override
    22             public void onResponse(String response) {
    23                 try {
    24                     addTextToResult("-->使用StringRequest用Get方式获取JSON数据
    ");
    25                     manageResponse(response);
    26                 } catch (Exception e) {
    27                     e.printStackTrace();
    28                 }
    29             }
    30         }, new Response.ErrorListener() {
    31             @Override
    32             public void onErrorResponse(VolleyError volleyError) {
    33                 addTextToResult(volleyError.toString());
    34             }
    35         });
    36         // 给Volley的Request请求对象标注TAG,并加入到全局请求队列中
    37         stringRequestGet.setTag("StringRequestGet");
    38         MyApplication.getRequestQueue().add(stringRequestGet);
    39     }
    40 
    41     // 使用POST方式从服务端获取到JSON数据并加以解析
    42     private void volleyPost() {
    43         // 使用StringRequest获取JSON数据
    44         String url = BASE_URL;
    45         StringRequest stringRequestPost = new StringRequest(Method.POST, url, new Response.Listener<String>() {
    46             @Override
    47             public void onResponse(String response) {
    48                 try {
    49                     addTextToResult("-->使用StringRequest用Post方式获取JSON数据
    ");
    50                     manageResponse(response);
    51                 } catch (Exception e) {
    52                     e.printStackTrace();
    53                 }
    54             }
    55         }, new Response.ErrorListener() {
    56             @Override
    57             public void onErrorResponse(VolleyError volleyError) {
    58                 addTextToResult(volleyError.toString());
    59             }
    60         }) {
    61             @Override
    62             protected Map<String, String> getParams() throws AuthFailureError {
    63                 Map<String, String> hashMap = new HashMap<>();
    64                 hashMap.put("key", "person");
    65                 return hashMap;
    66             }
    67         };
    68         stringRequestPost.setTag("StringRequestPost");
    69         MyApplication.getRequestQueue().add(stringRequestPost);
    70     }
    71 
    72     // 将参数中的文本添加到界面上的TextView中(在原文本的基础上添加)
    73     private void addTextToResult(String text) {
    74         String currentText = result.getText().toString();
    75         currentText += text;
    76         result.setText(currentText);
    77     }
    78 
    79     // 将使用Volley获取到的服务端JSON数据进行解析后添加到结果TextView中
    80     private void manageResponse(String response) {
    81         try {
    82             JSONObject jsonObject = new JSONObject(response).getJSONObject("person");
    83             addTextToResult("姓名:" + jsonObject.getString("name") + "
    年龄:" + jsonObject.getInt("age") + "
    地址:" +
    84                     jsonObject.getString("address") + "
    
    ");
    85         } catch (Exception e) {
    86             e.printStackTrace();
    87         }
    88     }
    89 
    90     @Override
    91     protected void onStop() {
    92         // 结束Activity的同时销毁全局请求队列中的所有请求
    93         super.onStop();
    94         MyApplication.getRequestQueue().cancelAll("StringRequestGet");
    95         MyApplication.getRequestQueue().cancelAll("StringRequestPost");
    96     }
    97 }
    主界面MainActivity代码

    运行结果如下:

    四、Volley与Activity生命周期的联动

      所谓的和Activity生命周期的联动,就是在Activity被销毁的时候(调用Activity的onStop()方法的时候),同时销毁所有的Volley请求对象。代码已经包含在MainActivity的代码中,这里再贴一遍:

    1 @Override
    2 protected void onStop() {
    3     // 结束Activity的同时销毁全局请求队列中的所有请求
    4     super.onStop();
    5     MyApplication.getRequestQueue().cancelAll("StringRequestGet");
    6     MyApplication.getRequestQueue().cancelAll("StringRequestPost");
    7 }
    MainActivity的OnStop()方法

    五、Volley的简单的二次封装

      所谓的“二次封装”,就是把上面我们所做的工作——包括实例化StringRequest、为Request添加TAG、将Request放入请求队列中灯操作——都封装成一个类或一个方法,以便以后调用。为了达到封装的目的,我们需要建立两个类:第一个类是VolleyInterface抽象类,用来定义请求成功和请求失败的接口,通过接口回调,让用户可以在主界面自定义实现操作;第二个类是VolleyRequest类,封装GET和POST两种请求方式的模糊代码,结合VolleyInterface类中的接口,完成封装。以下是这两个类的代码:

     1 public abstract class VolleyInterface {
     2     private Context context;
     3     public static Response.Listener<String> listener; // 请求成功的监听器
     4     public static Response.ErrorListener errorListener; // 请求失败的监听器
     5 
     6     public VolleyInterface(Context context, Response.Listener<String> listener, Response.ErrorListener errorListener) {
     7         this.context = context;
     8         this.listener = listener;
     9         this.errorListener = errorListener;
    10     }
    11 
    12     // 提供给用户编写的请求成功后的操作的接口
    13     public abstract void onSuccess(String response);
    14 
    15     // 提供给用户编写的请求失败后的操作的接口
    16     public abstract void onError(VolleyError error);
    17 
    18     // 利用接口回调,封装StringRequest中的请求成功的接口
    19     public Response.Listener<String> loadingListener() {
    20         listener = new Response.Listener<String>() {
    21             @Override
    22             public void onResponse(String response) {
    23                 onSuccess(response);
    24             }
    25         };
    26         return listener;
    27     }
    28 
    29     // 利用接口回调,封装StringRequest中的请求失败的接口
    30     public Response.ErrorListener loadingErrorListener() {
    31         errorListener = new Response.ErrorListener() {
    32             @Override
    33             public void onErrorResponse(VolleyError error) {
    34                 onError(error);
    35             }
    36         };
    37         return errorListener;
    38     }
    39 }
    抽象类VolleyInterface中的代码
     1 public class VolleyRequest {
     2     private static StringRequest request;
     3     private static Context context;
     4 
     5     // 使用StringRequest用GET方式从服务端获取JSON数据的封装方法
     6     public static void RequestGet(Context context, String url, String tag, VolleyInterface vif) {
     7         MyApplication.getRequestQueue().cancelAll(tag);
     8         request = new StringRequest(Request.Method.GET, url, vif.loadingListener(), vif.loadingErrorListener());
     9         request.setTag(tag);
    10         MyApplication.getRequestQueue().add(request);
    11         MyApplication.getRequestQueue().start();
    12     }
    13 
    14     // 使用StringRequest用POST方式从服务端获取JSON数据的封装方法
    15     public static void RequestPost(Context context, String url, String tag, final Map<String, String> params, VolleyInterface vif) {
    16         MyApplication.getRequestQueue().cancelAll(tag);
    17         request = new StringRequest(Request.Method.POST, url, vif.loadingListener(), vif.loadingErrorListener()) {
    18             @Override
    19             protected Map<String, String> getParams() throws AuthFailureError {
    20                 return params;
    21             }
    22         };
    23         request.setTag(tag);
    24         MyApplication.getRequestQueue().add(request);
    25         MyApplication.getRequestQueue().start();
    26     }
    27 }
    VolleyRequest类中的代码

    以下是MainActivity类中的测试代码:

      1 public class MainActivity extends Activity {
      2     // 基本的URL地址(GET和POST都用到这个地址,只不过GET需要在URL上添加参数,而POST不需要)
      3     private static final String BASE_URL = "http://192.168.1.102:8080/VolleyServer/JsonServlet";
      4     private TextView result;
      5 
      6     @Override
      7     protected void onCreate(Bundle savedInstanceState) {
      8         super.onCreate(savedInstanceState);
      9         setContentView(R.layout.content_main);
     10         result = (TextView) findViewById(R.id.result);
     11 
     12         volleyGet();
     13         volleyPost();
     14         customGet();
     15         customPost();
     16     }
     17 
     18     // 使用GET方式从服务端获取到JSON数据并加以解析
     19     private void volleyGet() {
     20         // 使用StringRequest获取JSON数据
     21         String url = BASE_URL + "?key=person";
     22         StringRequest stringRequestGet = new StringRequest(Method.GET, url, new Response.Listener<String>() {
     23             @Override
     24             public void onResponse(String response) {
     25                 try {
     26                     addTextToResult("-->使用StringRequest用Get方式获取JSON数据
    ");
     27                     manageResponse(response);
     28                 } catch (Exception e) {
     29                     e.printStackTrace();
     30                 }
     31             }
     32         }, new Response.ErrorListener() {
     33             @Override
     34             public void onErrorResponse(VolleyError volleyError) {
     35                 addTextToResult(volleyError.toString());
     36             }
     37         });
     38         // 给Volley的Request请求对象标注TAG,并加入到全局请求队列中
     39         stringRequestGet.setTag("StringRequestGet");
     40         MyApplication.getRequestQueue().add(stringRequestGet);
     41     }
     42 
     43     // 使用POST方式从服务端获取到JSON数据并加以解析
     44     private void volleyPost() {
     45         // 使用StringRequest获取JSON数据
     46         String url = BASE_URL;
     47         StringRequest stringRequestPost = new StringRequest(Method.POST, url, new Response.Listener<String>() {
     48             @Override
     49             public void onResponse(String response) {
     50                 try {
     51                     addTextToResult("-->使用StringRequest用Post方式获取JSON数据
    ");
     52                     manageResponse(response);
     53                 } catch (Exception e) {
     54                     e.printStackTrace();
     55                 }
     56             }
     57         }, new Response.ErrorListener() {
     58             @Override
     59             public void onErrorResponse(VolleyError volleyError) {
     60                 addTextToResult(volleyError.toString());
     61             }
     62         }) {
     63             @Override
     64             protected Map<String, String> getParams() throws AuthFailureError {
     65                 Map<String, String> hashMap = new HashMap<>();
     66                 hashMap.put("key", "person");
     67                 return hashMap;
     68             }
     69         };
     70         stringRequestPost.setTag("StringRequestPost");
     71         MyApplication.getRequestQueue().add(stringRequestPost);
     72     }
     73 
     74     // 使用二次封装的方法进行GET请求
     75     private void customGet() {
     76         VolleyRequest.RequestGet(this, BASE_URL + "?key=person", "CustomRequestGet", new VolleyInterface(this, VolleyInterface.listener, VolleyInterface.errorListener) {
     77             @Override
     78             public void onSuccess(String response) {
     79                 addTextToResult("-->使用VolleyRequest用GET方式获取JSON数据
    ");
     80                 manageResponse(response);
     81             }
     82 
     83             @Override
     84             public void onError(VolleyError error) {
     85                 addTextToResult(error.toString());
     86             }
     87         });
     88     }
     89 
     90     // 使用二次封装的方法进行POST请求
     91     private void customPost() {
     92         HashMap<String, String> hashMap = new HashMap<>();
     93         hashMap.put("key", "person");
     94         VolleyRequest.RequestPost(this, BASE_URL, "CustomRequestPost", hashMap, new VolleyInterface(this, VolleyInterface.listener, VolleyInterface.errorListener) {
     95             @Override
     96             public void onSuccess(String response) {
     97                 addTextToResult("-->使用VolleyRequest用POST方式获取JSON数据
    ");
     98                 manageResponse(response);
     99             }
    100 
    101             @Override
    102             public void onError(VolleyError error) {
    103                 addTextToResult(error.toString());
    104             }
    105         });
    106     }
    107 
    108     // 将参数中的文本添加到界面上的TextView中(在原文本的基础上添加)
    109     private void addTextToResult(String text) {
    110         String currentText = result.getText().toString();
    111         currentText += text;
    112         result.setText(currentText);
    113     }
    114 
    115     // 将使用Volley获取到的服务端JSON数据进行解析后添加到结果TextView中
    116     private void manageResponse(String response) {
    117         try {
    118             JSONObject jsonObject = new JSONObject(response).getJSONObject("person");
    119             addTextToResult("姓名:" + jsonObject.getString("name") + "
    年龄:" + jsonObject.getInt("age") + "
    地址:" +
    120                     jsonObject.getString("address") + "
    
    ");
    121         } catch (Exception e) {
    122             e.printStackTrace();
    123         }
    124     }
    125 
    126     @Override
    127     protected void onStop() {
    128         // 结束Activity的同时销毁全局请求队列中的所有请求
    129         super.onStop();
    130         MyApplication.getRequestQueue().cancelAll("StringRequestGet");
    131         MyApplication.getRequestQueue().cancelAll("StringRequestPost");
    132         MyApplication.getRequestQueue().cancelAll("CustomRequestGet");
    133         MyApplication.getRequestQueue().cancelAll("CustomRequestPost");
    134     }
    135 }
    第二次测试的代码

    运行结果如下图所示:

    六、Volley获取网络图片

      Volley获取网络图片有三种方式。第一种是使用ImageRequest获取网络图片,加载到Android自带的ImageView中;第二种是使用ImageLoader结合图片缓存获取网络图片,加载到Android自带的ImageView中;第三种是使用ImageLoader结合图片缓存获取网络图片,加载到Volley中提供的NetworkImageView中。下面是将这三种方法在同一个Activity中演示的代码:

     1 public class MainActivity extends Activity {
     2     private static final String IMAGE_URL = "http://www.baidu.com/img/bdlogo.png";
     3     private ImageView image, image2;
     4     private NetworkImageView image3;
     5 
     6     @Override
     7     protected void onCreate(Bundle savedInstanceState) {
     8         super.onCreate(savedInstanceState);
     9         setContentView(R.layout.content_main);
    10         image = (ImageView) findViewById(R.id.image);
    11         image2 = (ImageView) findViewById(R.id.image2);
    12         image3 = (NetworkImageView) findViewById(R.id.image3);
    13 
    14         // Volley加载网络图片
    15         volleyImageLoad();
    16         volleyImageCache();
    17         volleyNetworkImageLoad();
    18     }
    19 
    20     // 使用ImageRequest获取网络图片,加载到Android自带的ImageView中
    21     private void volleyImageLoad() {
    22         ImageRequest request = new ImageRequest(IMAGE_URL, new Response.Listener<Bitmap>() {
    23             @Override
    24             public void onResponse(Bitmap bitmap) {
    25                 image.setImageBitmap(bitmap);
    26             }
    27         }, 100, 100, Bitmap.Config.RGB_565, new Response.ErrorListener() {
    28             @Override
    29             public void onErrorResponse(VolleyError volleyError) {
    30                 image.setImageResource(R.mipmap.ic_launcher);
    31             }
    32         });
    33         request.setTag("ImageRequest");
    34         MyApplication.getRequestQueue().add(request);
    35     }
    36 
    37     // 使用ImageLoader结合图片缓存获取网络图片,加载到Android自带的ImageView中
    38     private void volleyImageCache() {
    39         ImageLoader imageLoader = new ImageLoader(MyApplication.getRequestQueue(), new BitmapCache());
    40         ImageLoader.ImageListener listener = imageLoader.getImageListener(image2, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
    41         imageLoader.get(IMAGE_URL, listener);
    42     }
    43 
    44     // 使用ImageLoader结合图片缓存获取网络图片,加载到Volley中提供的NetworkImageView中
    45     private void volleyNetworkImageLoad() {
    46         ImageLoader imageLoader = new ImageLoader(MyApplication.getRequestQueue(), new BitmapCache());
    47         image3.setDefaultImageResId(R.mipmap.ic_launcher);
    48         image3.setErrorImageResId(R.mipmap.ic_launcher);
    49         image3.setImageUrl(IMAGE_URL, imageLoader);
    50     }
    51 
    52     @Override
    53     protected void onStop() {
    54         // 结束Activity的同时销毁全局请求队列中的所有请求
    55         super.onStop();
    56         MyApplication.getRequestQueue().cancelAll("ImageRequest");
    57     }
    58 }
    MainActivity的代码
     1 public class BitmapCache implements ImageLoader.ImageCache {
     2     public LruCache<String, Bitmap> cache;
     3     public int maxCacheLength = 10 * 1024 * 1024;
     4 
     5     @SuppressLint("NewApi")
     6     public BitmapCache() {
     7         cache = new LruCache<String, Bitmap>(maxCacheLength) {
     8             @Override
     9             protected int sizeOf(String key, Bitmap value) {
    10                 return value.getRowBytes() * value.getHeight();
    11             }
    12         };
    13     }
    14 
    15     @SuppressLint("NewApi")
    16     @Override
    17     public Bitmap getBitmap(String key) {
    18         return cache.get(key);
    19     }
    20 
    21     @SuppressLint("NewApi")
    22     @Override
    23     public void putBitmap(String key, Bitmap value) {
    24         cache.put(key, value);
    25     }
    26 }
    图片缓存类BitmapCache

    运行结果如下图所示:

    注:第一张图是模糊的,可见用ImageRequest获取到的图片质量不如后两种方法。

    最后附上  Volley用到的JAR包

  • 相关阅读:
    webpack4配置详解之常用插件分享
    eslint 配置
    获取数组的随机数
    封装一个拖拽
    R语言常用语法和用法
    关于异或操作和它的算法题
    算法题:整形数组找a和b使得a+b=n
    最小生成树的一些证明
    python multiprocessing 使用
    python decorator的本质
  • 原文地址:https://www.cnblogs.com/blog-wzy/p/5197312.html
Copyright © 2011-2022 走看看