zoukankan      html  css  js  c++  java
  • Java基础知识强化之网络编程笔记23:Android网络通信之 Volley(Google开源网络通信库)

    联合网上资料学习:http://www.open-open.com/lib/view/open1451223702339.html

    一、Volley的介绍

    1. Volley简介 

      在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(Apache)等,今年的Google I/O 2013上,Volley发布了。Volley是Android平台上的网络通信库能使网络通信更快,更简单,更健壮
    这是Volley名称的由来: a burst or emission of many things or a large amount at once
    在Google IO的演讲上,其配图是一幅发射火弓箭的图,有点类似流星。见下图:

    其实,从这幅图,我们也可以看出来,Volley特别适合数据量不大但是通信频繁的场景

     2. Volley的引入背景:

    在以前,我们可能面临如下很多麻烦的问题。

    (1)比如以前从网上下载图片的步骤可能是这样的流程:

    • 在ListAdapter#getView()里开始图像的读取。
    • 通过AsyncTask等机制使用HttpURLConnection从服务器去的图片资源
    • 在AsyncTask#onPostExecute()里设置相应ImageView的属性。

    而在Volley下,只需要一个函数即可,详细见后面的例子。

    (2)再比如,屏幕旋转的时候,有时候会导致再次从网络取得数据。为了避免这种不必要的网络访问,我们可能需要自己写很多针对各种情况的处理,比如cache什么的。

    (3)再有,比如ListView的时候,我们滚动过快,可能导致有些网络请求返回的时候,早已经滚过了当时的位置,根本没必要显示在list里了,虽然我们可以通过ViewHolder来保持url等来实现防止两次取得,但是那些已经没有必须要的数据,还是会浪费系统的各种资源。

    等等……

    3.  Volley提供的功能:

    简单来说,它提供了如下的便利功能(优势):

       JSON,图像等的异步下载;

      • 网络请求的排序(scheduling)

       网络请求的优先级处理

       缓存

       多级别取消请求

      • 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求)

    二、Volley的使用:

    1. 引入Volley非常简单,首先,从git库先克隆一个下来:

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

    然后编译为jar包,再在自己的工程里import进来

    注意,这个库要求最低SDK版本为Froyo,即至少要设置android:minSdkVersion为 8 以上。

    也可以从Github代码库中获取:https://github.com/mcxiaoke/android-volley

    我自己也存放了Volley的jar包:http://download.csdn.net/detail/hebao5201314/9581002

    2. Volley实现JSON字符串GET请求:

    (1)构建一个RequestQueue

    1 RequestQueue requestQueue=Volley.newRequestQueue(this);//这里的this指的是Context

    (2)创建一个Request

    (3)将Request 添加到RequestQueue

    注:

    在构建JsonObjectRequest对象时,需要四个参数:

    个参数代表http方法;

    个参数代表访问Url;

    个和第参数分别是 响应监听响应错误监听,分别需要覆写onResponse()onErrorResponse()方法;RequestQueue将会执行请求,并将响应回调onResponse()方法,所以需要在onResponse()方法中实现自己的业务逻辑。

    代码如下:

     1 //获取Json字符串
     2     public void getJSONVolley() {
     3          RequestQueue requestQueue = Volley.newRequestQueue(this);
     4          String JSONDateUrl = "http://www.wwtliu.com/jsondata.html";
     5          /**
     6           * JsonObjectRequest(int method, String url, JSONObject jsonRequest, 
     7           *                Listener<JSONObject> listener, ErrorListener errorListener)
     8           */
     9          JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, JSONDateUrl,  null,
    10                  new Response.Listener<JSONObject>() {
    11 
    12                     public void onResponse(JSONObject response) {
    13                         System.out.println("response="+response);
    14                         
    15                     }
    16              
    17                 }, new Response.ErrorListener() {
    18                     public void onErrorResponse(com.android.volley.VolleyError arg0) {
    19                         System.out.println("对不起,有问题");
    20                     };
    21                 }
    22             );
    23          
    24          requestQueue.add(jsonObjectRequest);
    25     }

    效果如下:

    3. Volley实现异步加载图片:

    (1)首先开启Apache服务器,在Apache服务器中存放一个图片text.jpg,如下:

    使用360浏览器访问这个text.jpg文件,结果如下:

    说明这里的Apache服务器是开启成功,可以正常访问。

    (2)新建一个Android工程,命名为"MyVolley",如下:

    (3)我们先看看布局文件activity_main.xml,如下:

    这个布局是自适应显示图片的。

     1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:tools="http://schemas.android.com/tools"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:paddingBottom="@dimen/activity_vertical_margin"
     6     android:paddingLeft="@dimen/activity_horizontal_margin"
     7     android:paddingRight="@dimen/activity_horizontal_margin"
     8     android:paddingTop="@dimen/activity_vertical_margin"
     9     tools:context="com.himi.myvolley.MainActivity" >
    10 
    11     <ImageView
    12         android:id="@+id/iv"
    13         android:layout_width="wrap_content"
    14         android:layout_height="wrap_content"
    15         android:layout_alignParentLeft="true"
    16         android:layout_alignParentTop="true"
    17         android:layout_marginLeft="30dp"
    18         android:layout_marginTop="16dp" />
    19 
    20 </RelativeLayout>

     

    (4)MainActivity.java:

     1 package com.himi.myvolley;
     2 
     3 import org.json.JSONObject;
     4 
     5 import android.app.Activity;
     6 import android.graphics.Bitmap;
     7 import android.os.Bundle;
     8 import android.util.LruCache;
     9 import android.widget.ImageView;
    10 
    11 import com.android.volley.Request;
    12 import com.android.volley.RequestQueue;
    13 import com.android.volley.Response;
    14 import com.android.volley.toolbox.ImageLoader;
    15 import com.android.volley.toolbox.ImageLoader.ImageCache;
    16 import com.android.volley.toolbox.ImageLoader.ImageListener;
    17 import com.android.volley.toolbox.JsonObjectRequest;
    18 import com.android.volley.toolbox.Volley;
    19 
    20 /**
    21  * Volley是Android平台网络通信库:更快,更简单,更健壮。
    22  * volley提供的功能:
    23  * 1. JSON、图片(异步)
    24  * 2. 网络请求的排序
    25  * 3. 网络请求的优先级处理
    26  * 4. 缓存
    27  * 5. 多级别的取消请求
    28  * 6. 与Activity生命周期联动(Activity结束时同时取消所有网络请求)
    29  *
    30  *
    31  *    获取Volley()
    32  *  git clone https://android.googlesource.com/platform/frameworks/volley
    33  */
    34 public class MainActivity extends Activity {
    35     private ImageView iv1;
    36 
    37     @Override
    38     protected void onCreate(Bundle savedInstanceState) {
    39         super.onCreate(savedInstanceState);
    40         setContentView(R.layout.activity_main);
    41         init();
    42         //加载网络图片
    43         loadImageVolley();
    44     }
    45     
    46     
    47     public void init() {
    48         iv1 = (ImageView) findViewById(R.id.iv);
    49     }
    50 
    51     
    52     //异步加载图片
    53   
    54     public void loadImageVolley() {
    55         String imageurl = "http://49.123.72.145/text.jpg";
    56         RequestQueue requestQueue = Volley.newRequestQueue(this);
    57         final LruCache<String, Bitmap> lurcache = new LruCache<String, Bitmap>(20);
    58         ImageCache imageCache = new ImageCache() {
    59             
    60             //返回当前图片
    61             public Bitmap getBitmap(String key) {        
    62                 return lurcache.get(key);
    63             }
    64             
    65             //缓存图片资源
    66             public void putBitmap(String key, Bitmap value) {
    67                 lurcache.put(key, value);
    68             }
    69             
    70         };
    71         
    72         ImageLoader imageLoader = new ImageLoader(requestQueue, imageCache);
    73         /**
    74          * getImageListener(ImageView view, int defaultImageResId, int errorImageResId)
    75          *
    76          */
    77         ImageListener listener = imageLoader.getImageListener(iv1, R.drawable.ic_launcher, 
    78                  R.drawable.ic_launcher);
    79         imageLoader.get(imageurl, listener);
    80     }
    81 
    82 }

    这里要使用到网络,所以我们这里在AndroidMainfest.xml添加网络权限,如下:

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

    (5)布署程序到模拟器上,如下:

    4. Volley使用NetWorkImageView:

    Volley提供了一个新的控件NetworkImageView来代替传统的ImageView,这个控件的图片属性可以通过:

    mImageView.setImageUrl(url, imageLoader)

    来设定。而且,这个控件在被从父控件detach的时候,会自动取消网络请求的,即完全不用我们担心相关网络请求的生命周期问题。

    (1)这里我们3的项目中展示NetWorkImageView的使用,如下我们首先来到布局文件activity_main.xml,如下:

     1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:tools="http://schemas.android.com/tools"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:paddingBottom="@dimen/activity_vertical_margin"
     6     android:paddingLeft="@dimen/activity_horizontal_margin"
     7     android:paddingRight="@dimen/activity_horizontal_margin"
     8     android:paddingTop="@dimen/activity_vertical_margin"
     9     tools:context="com.himi.myvolley.MainActivity" >
    10 
    11     <ImageView
    12         android:id="@+id/iv"
    13         android:layout_width="wrap_content"
    14         android:layout_height="wrap_content"
    15         android:layout_alignParentLeft="true"
    16         android:layout_alignParentTop="true"
    17         android:layout_marginLeft="30dp"
    18         android:layout_marginTop="16dp" />
    19 
    20     <com.android.volley.toolbox.NetworkImageView
    21         android:id="@+id/imageView1"
    22         android:layout_width="wrap_content"
    23         android:layout_height="wrap_content"
    24         android:layout_centerHorizontal="true"
    25         android:layout_centerVertical="true"
    26          />
    27 
    28 </RelativeLayout>

    (2)然后是MainActivity.java,如下:

      1 package com.himi.myvolley;
      2 
      3 import org.json.JSONObject;
      4 
      5 import android.app.Activity;
      6 import android.graphics.Bitmap;
      7 import android.os.Bundle;
      8 import android.util.LruCache;
      9 import android.widget.ImageView;
     10 
     11 import com.android.volley.Request;
     12 import com.android.volley.RequestQueue;
     13 import com.android.volley.Response;
     14 import com.android.volley.toolbox.ImageLoader;
     15 import com.android.volley.toolbox.ImageLoader.ImageCache;
     16 import com.android.volley.toolbox.ImageLoader.ImageListener;
     17 import com.android.volley.toolbox.JsonObjectRequest;
     18 import com.android.volley.toolbox.NetworkImageView;
     19 import com.android.volley.toolbox.Volley;
     20 
     21 /**
     22  * Volley是Android平台网络通信库:更快,更简单,更健壮。
     23  * volley提供的功能:
     24  * 1. JSON、图片(异步)
     25  * 2. 网络请求的排序
     26  * 3. 网络请求的优先级处理
     27  * 4. 缓存
     28  * 5. 多级别的取消请求
     29  * 6. 与Activity生命周期联动(Activity结束时同时取消所有网络请求)
     30  *
     31  *
     32  *    获取Volley()
     33  *  git clone https://android.googlesource.com/platform/frameworks/volley
     34  */
     35 public class MainActivity extends Activity {
     36     private ImageView iv1;
     37     private NetworkImageView iv2;
     38 
     39     @Override
     40     protected void onCreate(Bundle savedInstanceState) {
     41         super.onCreate(savedInstanceState);
     42         setContentView(R.layout.activity_main);
     43         init();
     44         //getJSONVolley();
     45         NetWorkImageViewVolley();
     46         
     47     }
     48     
     49     
     50     public void init() {
     51         iv1 = (ImageView) findViewById(R.id.iv);
     52         iv2 = (NetworkImageView) findViewById(R.id.imageView1);
     53         loadImageVolley();
     54     }
     55 
     56     //获取Json字符串
     57     public void getJSONVolley() {
     58          RequestQueue requestQueue = Volley.newRequestQueue(this);
     59          String JSONDateUrl = "http://www.wwtliu.com/jsondata.html";
     60          /**
     61           * JsonObjectRequest(int method, String url, JSONObject jsonRequest, 
     62           *                Listener<JSONObject> listener, ErrorListener errorListener)
     63           */
     64          JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, JSONDateUrl,  null,
     65                  new Response.Listener<JSONObject>() {
     66 
     67                     public void onResponse(JSONObject response) {
     68                         System.out.println("response="+response);
     69                         
     70                     }
     71              
     72                 }, new Response.ErrorListener() {
     73                     public void onErrorResponse(com.android.volley.VolleyError arg0) {
     74                         System.out.println("对不起,有问题");
     75                     };
     76                 }
     77             );
     78          
     79          requestQueue.add(jsonObjectRequest);
     80     }
     81     
     82     //异步加载图片
     83     //http://localhost/lesson-img.png
     84     public void loadImageVolley() {
     85         String imageurl = "http://49.123.72.145/text.jpg";
     86         RequestQueue requestQueue = Volley.newRequestQueue(this);
     87         final LruCache<String, Bitmap> lurcache = new LruCache<String, Bitmap>(20);
     88         ImageCache imageCache = new ImageCache() {
     89             
     90             //返回当前图片
     91             public Bitmap getBitmap(String key) {        
     92                 return lurcache.get(key);
     93             }
     94             
     95             //缓存图片资源
     96             public void putBitmap(String key, Bitmap value) {
     97                 lurcache.put(key, value);
     98             }
     99             
    100         };
    101         
    102         ImageLoader imageLoader = new ImageLoader(requestQueue, imageCache);
    103         /**
    104          * getImageListener(ImageView view, int defaultImageResId, int errorImageResId)
    105          *
    106          */
    107         ImageListener listener = imageLoader.getImageListener(iv1, R.drawable.ic_launcher, 
    108                  R.drawable.ic_launcher);
    109         imageLoader.get(imageurl, listener);
    110     }
    111     // Volley使用NetWorkImageView
    112     public void NetWorkImageViewVolley() {
    113         String imageUrl = "http://49.123.72.145/text.jpg";
    114         RequestQueue requestQueue = Volley.newRequestQueue(this);
    115         final LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(20);
    116         ImageCache imageCache = new ImageCache() {
    117 
    118             public Bitmap getBitmap(String key) {
    119                 // TODO 自动生成的方法存根
    120                 return lruCache.get(key);
    121             }
    122 
    123             public void putBitmap(String key, Bitmap value) {
    124                 lruCache.put(key, value);
    125                 
    126             }
    127             
    128         };
    129         
    130         ImageLoader imageLoader = new ImageLoader(requestQueue, imageCache);
    131         iv2.setTag("url");
    132         iv2.setImageUrl(imageUrl, imageLoader);
    133     }
    134 
    135 }

    其他代码不变,布署程序到模拟器上,效果如下:

    5. Volley的框架原理:

     Volley使用了线程池来作为基础结构,主要分为主线程,cache调度线程和 network调度线程。

    主线程 和 cache调度线程 都只有一个,而network调度线程可以有多个,这样能解决比并行问题。如下图:

    • 优点:Volley简化了网络通信这块的开发,特别是针对数据量不大但网络通信频繁,对JSON对象,图片加载这两块进行了很好的封装和支持,

    • 缺点:对大数据(large payloads ),流媒体,这些case不能很好的支持,还需要使用原始的方法,比如Download Manager等。

    其中蓝色的是主线程绿色的是缓存线程黄色的是网络线程

    (1)当一个Request请求添加到RequestQueue请求队列中,Volley就开始工作了。RequestQueue请求队列中持有一个CacheDispatcher缓存调度器和一组NetworkDispatcher网络调度器。

    (2)RequestQueue会先叫来CacheDispatcher缓存调度器,让他去看看,当前请求的数据在不在cache中

         2.1.当前的数据在cache中,那就把数据从cache中取出来,然后经过一番加工,将加工好的数据交付给主线程

         2.2.当前数据没在cache中,进行第3步

    (3)进行到了这一步,那肯定是数据没有在缓存中,那只能去网络中获取了,这时候RequestQueue会叫来NetworkDispatcher网络调度器NetworkDispatcher可是有一大帮子呢,其实这是一个线程池,默认情况下会启动4个线程去网络下载数据。所以RequestQueue把当前闲着的NetworkDispatcher叫来,给他们分配任务。

    (4)拿到任务的NetworkDispatcher就会去网络上下载数据了,与此同时,他会判断下载到的数据能否写入到cache缓存中,如果可以的话就写入cache,以便于下一次直接从cache中获取到数据。最后,将数据加工,交付给主线程。

    如果在一个Activity里面启动了网络请求,而在这个网络请求还没返回结果的时候,如果Activity被结束了,则我们需要写如下代码作为防守:

    1 @Override 
    2 public void onPostExecute(Result r) {  
    3     if (getActivity() == null) {  
    4         return;  
    5     }  
    6     // ...  
    7 }  

    Activity被终止之后,如果继续使用其中的Context等,除了无辜的浪费CPU,电池,网络等资源,有可能还会导致程序crash,所以,我们需要处理这种一场情况。

    使用Volley的话,我们可以在Activity停止的时候,同时取消所有或部分未完成的网络请求。

    Volley里所有的请求结果会返回给主进程,如果在主进程里取消了某些请求,则这些请求将不会被返回给主线程。
    比如,可以针对某些个request做取消操作:

    1 @Override  
    2 public void onStop() {  
    3     for (Request <?> req : mInFlightRequests) {  
    4         req.cancel();  
    5     }  
    6     ...  
    7 }  

    或者,取消这个队列里的所有请求:

    1 @Override
    2  pubic void onStop() {  
    3     mRequestQueue.cancelAll(this);  
    4     ...  
    5 }  

    也可以根据RequestFilter或者Tag来终止某些请求:

    1 @Override public void onStop() {  
    2     mRequestQueue.cancelAll( new RequestFilter() {})  
    3     ...  
    4     // or  
    5     mRequestQueue.cancelAll(new Object());  
    6     ...  
  • 相关阅读:
    java实现链队列
    java使用链栈实现迷宫求解
    java使用链栈实现数制转换
    java实现链栈
    java实现顺序栈
    java实现双向循环链表
    java实现循环链表
    java实现单链表
    java实现顺序链表
    Osmocom-BB中cell_log的多种使用姿势
  • 原文地址:https://www.cnblogs.com/hebao0514/p/4891139.html
Copyright © 2011-2022 走看看