Android 网络通信——Volley

来源:互联网 发布:成都 python兼职 编辑:程序博客网 时间:2024/06/03 09:23

  Volley 是 Google 推出的 Android 异步网络请求框架和图片加载框架。在 Google I/O 2013 大会上发布。

Volley简介

Volley 的主要特点
1. 适合数据量小,通信频繁的网络操作
2. 扩展性强。Volley 中大多是基于接口的设计,可配置性强。
3. 一定程度符合 Http 规范,包括返回 ResponseCode(2xx、3xx、4xx、5xx)的处理,请求头的处理,缓存机制的支持等。并支持重试及优先级定义。
4. 默认 Android2.3 及以上基于 HttpURLConnection,2.3 以下基于 HttpClient 实现。
5. 提供简便的图片加载工具。

Volley实现的基本步骤:

  首先创建一个请求队列,然后创建一个请求,将请求添加到请求队列中,Volley对队列中的请求进行处理。

Volley原理解析:

  我们参照下图理解一下Volley处理网络请求的原理:
  
这里写图片描述

图中的概念:

Volley:
  Volley 对外暴露的 API,通过 newRequestQueue(…) 函数新建并启动一个请求队列RequestQueue。
Request:
  表示一个请求的抽象类。StringRequest、JsonRequest、ImageRequest都是它的子类,表示某种类型的请求。
RequestQueue:
  表示请求队列,里面包含一个CacheDispatcher(用于处理走缓存请求的调度线程)、NetworkDispatcher数组(用于处理走网络请求的调度线程),一个ResponseDelivery(返回结果分发接口),通过 start() 函数启动时会启动CacheDispatcher和NetworkDispatchers。
CacheDispatcher:
  一个线程,用于调度处理走缓存的请求。启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher去调度处理。
NetworkDispatcher:
  一个线程,用于调度处理走网络的请求。启动后会不断从网络请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理,并判断结果是否要进行缓存。
ResponseDelivery:
  返回结果分发接口,目前只有基于ExecutorDelivery的在入参 handler 对应线程内进行分发。
HttpStack:
  处理 Http 请求,返回请求结果。目前 Volley 中有基于 HttpURLConnection 的HttpURLStack和 基于 Apache HttpClient 的HttpClientStack。
Network:
  调用HttpStack处理请求,并将结果转换为可被ResponseDelivery处理的NetworkResponse。
Cache:
  缓存请求结果,Volley 默认使用的是基于 sdcard 的DiskBasedCache。NetworkDispatcher得到请求结果后判断是否需要存储在 Cache,CacheDispatcher会从 Cache 中取缓存结果。

  首先当有Request被添加到请求队列中请求网络时,Volley会先去Cache中查看是否有请求相同的URL地址的缓存,如果不久前请求过,则会调用CacheDispatcher线程处理获得缓存的返回结果;如果之前没有请求过,则会调用NetworkDispatcher线程处理请求,查看请求队列中有没有空闲的线程,如果有,则调用该线程访问URL,如果没有空闲的线程,则等待线程空闲下来。

Volley StringRequest使用

  在前面我们已经讲了Volley基本使用,现在我们来看代码的实现:
1. 新建一个消息队列RequestQueue的对象,通过调用Volley.newRequestQueue(getApplicationContext())获得该对象。

RequestQueue queue = Volley.newRequestQueue(getApplicationContext());

2. 创建字符串请求消息队列的StringRequest 的请求。传入四个参数,第一个是请求的方法,第二个是请求的url,第三个参数是请求成功回调的方法,第四个是请求失败回调的方法。

GET方式请求:

 StringRequest request = new StringRequest(Request.Method.GET, "http://192.168.0.44:8080/MyServiceTest/MyTestServlet",                        new Response.Listener<String>() {                            @Override                            public void onResponse(String response) {                            }                        },                        new Response.ErrorListener() {                            @Override                            public void onErrorResponse(VolleyError error) {                                           }                        });

POST方式请求:

 StringRequest request = new StringRequest(Request.Method.POST, "http://192.168.0.44:8080/MyServiceTest/MyTestServlet",                        new Response.Listener<String>() {                            @Override                            public void onResponse(String response) {                                                    }                        },                        new Response.ErrorListener() {                            @Override                            public void onErrorResponse(VolleyError error) {                            }                        }){                        //重写了StringRequest中的getParams()方法。                    @Override                    protected Map<String, String> getParams() throws AuthFailureError {                        HashMap<String, String > map = new HashMap<>();                        map.put("username","zhangsan");                        return map;                    }                };

3. 请求队列调用add方法,将请求添加到请求队列中

queue.add(request);

Volley 单例使用

  我们要知道,如果我们按照上面的方式实现,那么每次调用都会产生一个新的请求队列,这样每次发出请求都会添加到一个新的请求队列中。而我们想要的结果是每次的请求添加到同一个请求队列中,这样我们就需要使每次产生的请求队列是同一个,这就用到了“单例设计模式”。
实现代码如下:

public class MySingleton{    private String lock = "lock";    private static MySingleton mInstance;    private RequestQueue mRequestQueue;    private static Context mCtx;    private MySingleton(Context context) {        mCtx = context;        mRequestQueue = getRequestQueue();    }    public static MySingleton getInstance(Context context){        if(mInstance == null){            synchronized (lock){                if(mInstance == null){                    mInstance = new MySingleton(context);                }            }                   }        return mInstance;    }    public RequestQueue getRequestQueue(){             if(mRequestQueue == null){                     mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());                 }             return mRequestQueue;         }    //将请求添加到队列中    public void addToRequestQueue(Request req){        getRequestQueue().add(req);    }}

  Activity中我们通过按钮的点击事件连接网络,然后将返回数据显示在TextView中:

public class VolleyBaseActivity extends Activity implements OnClickListener {    private Button mButtonVolleyGet;    private TextView mTextViewContent;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_volley_base);        mButtonVolleyGet = (Button) findViewById(R.id.button_volleyget);        mTextViewContent = (TextView) findViewById(R.id.textview_content);        mButtonVolleyGet.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.button_volleyget:                //创建请求                StringRequest request = new StringRequest(Request.Method.POST, "http://192.168.0.44:8080/MyServiceTest/MyTestServlet",                        new Response.Listener<String>() {                            @Override                            public void onResponse(String response) {                                mTextViewContent.setText(response);//将连接成功后,返回的信息输出到TextView中。                            }                        },                        new Response.ErrorListener() {                            @Override                            public void onErrorResponse(VolleyError error) {                                mTextViewContent.setText("网络连接错误");//如果连接失败,在TextView出显示信息"网络连接失败"。                            }                        }) {                    @Override                    protected Map<String, String> getParams() throws AuthFailureError {                        HashMap<String, String> map = new HashMap<>();                        map.put("username", "zhangsan");                        return map;                    }                };                //创建请求队列并将请求添加到请求队列中                MySingleton.getInstance(getApplicationContext()).addToRequestQueue(request);                break;            default:                break;        }    }}

这里写图片描述

Volley ImageRequest使用

  图片加载请求是使用ImageRequest的,但是ImageRequest的使用比较繁琐,Android中就将其进行了封装,使用ImageLoader。我们将ImageLoader也采用单例设计模式。

public class MySingleton{    private static MySingleton mInstance;    private RequestQueue mRequestQueue;//消息队列    private ImageLoader mImageLoader;//ImageLoader对象    private static Context mCtx;    private MySingleton(Context context) {        mCtx = context;        mRequestQueue = getRequestQueue();        mImageLoader = getImageLoader();    }    public static synchronized MySingleton getInstance(Context context){        if(mInstance == null){            mInstance = new MySingleton(context);         }        return mInstance;    }    public RequestQueue getRequestQueue(){             if(mRequestQueue == null){                     mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());                 }             return mRequestQueue;         }    public ImageLoader getImageLoader(){        if(mImageLoader==null){            mImageLoader = new ImageLoader(getRequestQueue(), new ImageLoader.ImageCache(){                private final LruCache<String,Bitmap>  cache = new LruCache<String,Bitmap>(20);//设置图片缓存                @Override                public Bitmap getBitmap(String url) {                    return null;                }                @Override                public void putBitmap(String url, Bitmap bitmap) {                }            });        }        return mImageLoader;    }    //将请求添加到队列中    public void addToRequestQueue(Request req){        getRequestQueue().add(req);    }}

  Activity中我们通过点击按钮将图片显示出来。这里我们先显示网络图片使用NetworkImageView,因为NetworkImageView加载网络图片比较简单,只需要调用setImageUrl(URL url, ImageLoader loader)方法即可,方法传入两个参数,第一个是图片的URL地址,第二个是ImageLoader对象。

public class ImageRequestActivity extends Activity implements View.OnClickListener {    private Button mButtonGetImage;    private NetworkImageView mNetworkImageView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_image_request);        mButtonGetImage = (Button) findViewById(R.id.button_get_image);        mNetworkImageView = (NetworkImageView) findViewById(R.id.imageview);        mButtonGetImage.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()){            case R.id.button_get_image:                //获得ImageLoader的对象。                ImageLoader loader = MySingleton.getInstance(getApplicationContext()).getImageLoader();                //调用setImageUrl方法               mNetworkImageView.setImageUrl("http://pic.nipic.com/2007-11-09/2007119122519868_2.jpg", loader);                break;            default:                break;        }    }}

这里写图片描述

  JsonRequest的使用与StringRequest的使用是相同的,只不过在后期对数据的处理不同。在此不在列举JsonRequest的使用。

0 0
原创粉丝点击