Android 网络通信——Volley

  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处理网络请求的原理:
  
Android 网络通信——Volley_第1张图片

图中的概念:

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;
        }
    }
}

Android 网络通信——Volley_第2张图片

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;
        }
    }
}

Android 网络通信——Volley_第3张图片

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

你可能感兴趣的:(android,网络,Volley)