1、volley简介
1.1、volley概述
1)volley其实是一个网络请求框架,相当于xutil的HttpUtil+BitmapUtil
2)Volley的特点:
1.支持高效并发访问get/post。
2.和Activity声明周期联动。
3.支持网络图片加载和本地图片存储。
4.支持访问排序:token
5.多级别取消请求
3)缺点
不适合进行数据的上传和下载。
1.2、Volley中两个核心类
1.2.1、Request:请求
1)StringRequest:返回字符串
2)JsonObjectRequest:返回json对象
解析json两种方式:
response.getString("name");//方式一:当key不存在会出现异常,不建议使用
response.optString("name");//方式二:key不存在,返回默认值,""
3)JsonArrayRequest:json数组
4)ImageRequest:返回bitmap对象。
ImageRequest构造函数几个重要参数:
new ImageRequest(arrayUrl, listener, maxWidth, maxHeight, decodeConfig, errorListener);
①maxWidth、maxHeight: //0显示原始图片大小,指定大小则会对图片压缩处理
②decodeConfig:
Config.ALPHA_8->8位->一个字节
ARGB_4444:16位 2个字节
ARGB_8888 32位 4个字节
RGB_565 16位 2个字节
图片格式选择:
Volley使用RGB_565
xutil:RGB_565
UIL:ARGB_8888
1.1.2、RequestQueue:请求队列
volley网络请求队列的建立和取消。
2、Volley请求网络接口数据
2.1、Volley的get和post请求
2.2、Volley的网络请求队列的建立和取消队列请求
2.3、Volley与activity生命周期的联动
2.4、Volley的简单二次回掉封装
1)Volley的网络请求队列的建立
public class MyApplication extends Application { public static RequestQueue queues; @Override public void onCreate() { super.onCreate(); queues = Volley.newRequestQueue(getApplicationContext());//建立全局的请求队列 } public static RequestQueue getHttpQueues() { return queues; } }
2)Volley的get和post请求
public class MainActivity extends Activity { private ImageView imageView; private TextView textview; private String requestTag = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView) findViewById(R.id.imageView); textview = (TextView) findViewById(R.id.textview); }
private void volley_get() { // 错误url:String url = "ip.taobao.com/service/getIpInfo.php?ip=202.96.128.166" String url = "http://ip.taobao.com/service/getIpInfo.php?ip=202.96.128.166"; StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String response) { textview.setText(response); // Toast.makeText(MainActivity.this,response, Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // Toast.makeText(MainActivity.this,error.toString(), Toast.LENGTH_SHORT).show(); textview.setText(error.toString()); } } ); requestTag = "volley_get"; request.setTag(requestTag);//设置标记 MyApplication.getHttpQueues().add(request); } private void volley_getJson() { // 错误url:String url = "ip.taobao.com/service/getIpInfo.php?ip=202.96.128.166" String url = "http://ip.taobao.com/service/getIpInfo.php?ip=202.96.128.166"; JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { textview.setText(response.toString()); // Toast.makeText(MainActivity.this,response, Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // Toast.makeText(MainActivity.this,error.toString(), Toast.LENGTH_SHORT).show(); textview.setText(error.toString()); } } ); requestTag = "volley_getjson"; request.setTag(requestTag); MyApplication.getHttpQueues().add(request); }
private void volley_post() { // 错误url:String url = "ip.taobao.com/service/getIpInfo.php?ip=202.96.128.166" String url = "http://ip.taobao.com/service/getIpInfo.php?"; StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() { @Override public void onResponse(String response) { textview.setText(response); // Toast.makeText(MainActivity.this,response, Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // Toast.makeText(MainActivity.this,error.toString(), Toast.LENGTH_SHORT).show(); textview.setText(error.toString()); } } ){ @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> hashMap = new HashMap<String, String>(); hashMap.put("ip", "202.96.128.166"); return hashMap; } }; requestTag = "volley_post"; request.setTag(requestTag); MyApplication.getHttpQueues().add(request); } private void volley_postJson() { Map<String, String> hashMap = new HashMap<String, String>(); hashMap.put("phone", "13429667914"); hashMap.put("key", "335adcc4e891ba4e4be6d7534fd54c5d"); JSONObject jsonParams = new JSONObject(hashMap); // 错误url:String url = "ip.taobao.com/service/getIpInfo.php?ip=202.96.128.166" String url = "http://apis.juhe.cn/mobile/get?"; JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, url,jsonParams, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { textview.setText(response.toString()); // Toast.makeText(MainActivity.this,response, Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // Toast.makeText(MainActivity.this,error.toString(), Toast.LENGTH_SHORT).show(); textview.setText(error.toString()); } } ){ @Override public Map<String, String> getHeaders() { HashMap<String, String> headers = new HashMap<String, String>(); headers.put("Accept", "application/json"); headers.put("Content-Type", "application/json; charset=UTF-8"); return headers; } }; requestTag = "volley_postjson"; request.setTag(requestTag); MyApplication.getHttpQueues().add(request); }
3)cancelAll()方法,通过给定的tag值,将指定的队列全部取消请求。即与activity生命周期实现联动。
@Override protected void onStop() { super.onStop(); if (!"".equals(requestTag)) MyApplication.getHttpQueues().cancelAll(requestTag); }
4)volley的二次回调封装
get和post方法的封装
public class VolleyRequest { public static StringRequest stringRequest; public static Context context; public static void RequestGet(Context context,String url, String tag, VolleyInterface vif) { MyApplication.getHttpQueues().cancelAll(tag); stringRequest = new StringRequest(Request.Method.GET,url,vif.loadingListener(),vif.errorListener()); stringRequest.setTag(tag); MyApplication.getHttpQueues().add(stringRequest); // 不写也能执行 // MyApplication.getHttpQueues().start(); } public static void RequestPost(Context context,String url, String tag,final Map<String, String> params, VolleyInterface vif) { MyApplication.getHttpQueues().cancelAll(tag); stringRequest = new StringRequest(Request.Method.POST,url,vif.loadingListener(),vif.errorListener()) { @Override protected Map<String, String> getParams() throws AuthFailureError { return params; } }; stringRequest.setTag(tag); MyApplication.getHttpQueues().add(stringRequest); // 不写也能执行 // MyApplication.getHttpQueues().start(); } }
请求成功和失败的接口回调
public abstract class VolleyInterface { public Context context; public static Response.Listener<String> listener; public static Response.ErrorListener errorListener; public abstract void onMySuccess(String result); public abstract void onMyError(VolleyError error); public VolleyInterface (Context context, Response.Listener<String> listener, Response.ErrorListener errorListener) { this.context = context; this.listener = listener; this.errorListener = errorListener; } public Response.Listener<String> loadingListener() { listener = new Response.Listener<String>() { @Override public void onResponse(String response) { onMySuccess(response); } }; return listener; } public Response.ErrorListener errorListener() { errorListener = new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { onMyError(error); } }; return errorListener; } }
二次请求封装的使用
public class SecActivity extends Activity { private ImageView imageView; private TextView textview; private String requestTag = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sec); imageView = (ImageView) findViewById(R.id.imageView); textview = (TextView) findViewById(R.id.textview); } @Override protected void onStop() { super.onStop(); if (!"".equals(requestTag)) MyApplication.getHttpQueues().cancelAll(requestTag); } private void volley_get() { textview.setText("封装get 开始了"); // 错误url:String url = "ip.taobao.com/service/getIpInfo.php?ip=202.96.128.166" String url = "http://ip.taobao.com/service/getIpInfo.php?ip=202.96.128.166"; requestTag = "volley_post"; VolleyRequest.RequestGet(this, url, requestTag, new VolleyInterface(this, VolleyInterface.listener, VolleyInterface.errorListener) { @Override public void onMySuccess(String result) { JSONObject json = null; try { json = new JSONObject(result); } catch (JSONException e) { e.printStackTrace(); } textview.setText("GETresult=" + json.toString()); } @Override public void onMyError(VolleyError error) { textview.setText(error.toString()); } }); } private void volley_getJson() { Toast.makeText(this, "请自己实现get json的二次封装!",Toast.LENGTH_SHORT).show(); textview.setText("请自己实现get json的二次封装!"); } private void volley_post() { textview.setText("封装post String 开始了"); // 错误url:String url = "ip.taobao.com/service/getIpInfo.php?ip=202.96.128.166" String url = "http://ip.taobao.com/service/getIpInfo.php?"; requestTag = "volley_get"; Map<String, String> hashMap = new HashMap<String, String>(); hashMap.put("ip", "202.96.128.166"); VolleyRequest.RequestPost(this, url, requestTag, hashMap, new VolleyInterface(this, VolleyInterface.listener, VolleyInterface.errorListener) { @Override public void onMySuccess(String result) { JSONObject json = null; try { json = new JSONObject(result); } catch (JSONException e) { e.printStackTrace(); } textview.setText("POSTresult=" + json.toString()); } @Override public void onMyError(VolleyError error) { textview.setText(error.toString()); } }); } private void volley_postJson() { Toast.makeText(this, "自己实现post json的二次封装!",Toast.LENGTH_SHORT).show(); textview.setText("自己实现post json的二次封装!"); } }
3、Volley获取网络图片
1、ImageRequest
2、ImageLoder
3、NetworkImageView
public class ImagesActivity extends Activity { private ImageView imageView; private TextView textview; private NetworkImageView networkImageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_images); imageView = (ImageView) findViewById(R.id.imageView); textview = (TextView) findViewById(R.id.textview); networkImageView = (NetworkImageView) findViewById(R.id.networkImageView); } @Override protected void onStop() { super.onStop(); } // 获取图片 public void get_image_clicked(View view) { Log.i("TAG", "get_image_clicked"); get_image(); } // 获取图片缓存 public void get_imageloader_clicked(View view) { Log.i("TAG", "get_imageloader_clicked"); get_imageloader(); } // 用NetworkImageView获取图片 public void btn_get_network_image_clicked(View view) { Log.i("TAG", "btn_get_network_image_clicked"); btn_get_network_image(); } private void get_image() { textview.setText("获取图片开始了"); imageView.setImageBitmap(null); networkImageView.setImageBitmap(null); // 错误url:String url = "ip.taobao.com/service/getIpInfo.php?ip=202.96.128.166" // String url = "http://d.hiphotos.baidu.com/image/h%3D200/sign=31db160e2a738bd4db21b531918a876c/6a600c338744ebf8f1230decddf9d72a6159a797.jpg"; String url = "http://h.hiphotos.baidu.com/image/pic/item/d53f8794a4c27d1e3584e91b1fd5ad6edcc4384b.jpg"; ImageRequest request = new ImageRequest(url, new Response.Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { textview.setText("获取图片成功"); imageView.setImageBitmap(response); } }, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { textview.setText("获取图片错误"); imageView.setImageBitmap(null); } }); MyApplication.getHttpQueues().add(request); } private void get_imageloader() { textview.setText("获取图片开始了"); networkImageView.setImageBitmap(null); imageView.setImageBitmap(null); String url = "http://g.hiphotos.baidu.com/image/pic/item/21a4462309f790521631d9e908f3d7ca7bcbd53f.jpg"; ImageLoader loader = new ImageLoader(MyApplication.getHttpQueues(), new BitmapCache()); ImageLoader.ImageListener listener = ImageLoader.getImageListener(imageView, R.drawable.default_icon , R.drawable.error ); loader.get(url, listener); } private void btn_get_network_image() { String url = "http://g.hiphotos.baidu.com/image/pic/item/0ff41bd5ad6eddc487907ddd3cdbb6fd526633a5.jpg"; textview.setText("获取NetworkImageView图片开始了"); imageView.setImageBitmap(null); ImageLoader loader = new ImageLoader(MyApplication.getHttpQueues(), new BitmapCache()); networkImageView.setErrorImageResId(R.drawable.error2); networkImageView.setDefaultImageResId(R.drawable.default_icon); networkImageView.setImageUrl(url, loader); } }
3、Volley开发三部曲
①创建对应的Request对象
②创建RequestQueue请求队列
③将request对象添加到请求队列中
示例:
1)StringRequest(请求返回数据类型不确定的情况下)
// 创建对应的Request对象 StringRequest request = new StringRequest(url, new Listener<String>() { @Override public void onResponse(String response) { System.out.println(response); } }, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { System.out.println(error.getMessage()); } }); // 创建RequestQueue请求队列 RequestQueue requestQueue = Volley.newRequestQueue(context); // 添加到请求队列中 requestQueue.add(request); }
2) JsonObjectRequest
//1创建JsonObjectRequest对象 JsonObjectRequest request = new JsonObjectRequest(url, null, new Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { // 解析json数据 // response.get("name");//当key不存在时,会抛出异常,不建议使用 String name = response.optString("name");// 当key不存在时,返回默认值“”。 int age = response.optInt("age"); String school = response.optString("school"); System.out.println("name=" + name + ",age=" + age+ ",school=" + school); } }, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { System.out.println(error.getMessage()); } }); //2.创建requestqueue对象 RequestQueue requestQueue = Volley.newRequestQueue(context); //3.添加到请求队列中 requestQueue.add(request);
3)jsonArrayRequest
private void jsonArrayRequest() { JsonArrayRequest request = new JsonArrayRequest(arrayUrl, new Listener<JSONArray>() { /* * "name": "Steve Jobs", "age": 69, "school": "CMU", * "company": "Apple" */ @Override public void onResponse(JSONArray response) { for (int i = 0; i < response.length(); i++) { JSONObject jsonObject = response.optJSONObject(i); String name = jsonObject.optString("name"); int age = jsonObject.optInt("age"); String school = jsonObject.optString("school"); String company = jsonObject.optString("company"); System.out.println("name=" + name + ",age=" + age + ",school=" + school + ",compamy=" + company); } } }, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); RequestQueue requestQueue = Volley.newRequestQueue(context); requestQueue.add(request);
4)ImageRequest
private void imageRequest() { int maxWidth = 0; int maxHeight = 0; Config decodeConfig = Config.ALPHA_8;//8位表示一个字节 //1创建ImageRequest对象 ImageRequest request = new ImageRequest(imageUrl, new Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { // 请求成功返回bitmap对象 iv.setImageBitmap(response); } }, maxWidth, maxHeight, decodeConfig, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // TODO Auto-generated method stub } }); //2.创建RequestQueue对象 RequestQueue queue = Volley.newRequestQueue(context); //3.添加request到队列中 queue.add(request); }
4、Volley和Activity生命周期绑定
当activity销毁时,也应该取消网络访问,可在activity中的finish()方法中,取消网络访问。
HttpClient停止网络请求:
HttpClient.getConnectiontManager()
ClientConnectionManager.shutdown()停止访问网络
Volley取消网络
(1)RequestQueue.stop(),取消单个网络访问
(2)RequestQueue.cancleAll(tag)取消所有网络,
4、图片压缩核心内容
原理:BitmapFactory.Options
decodeOptions.inJustDecodeBounds = true;// 获得图片宽度和高度,图片不加载到内存中,图片很大也不会OOM
decodeOptions.inSampleSize:采样率,值为2的几次方,8表示按 1/8缩小
4.1、volley中的inSampleSize计算方式:
static int findBestSampleSize( int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) { double wr = (double) actualWidth / desiredWidth; double hr = (double) actualHeight / desiredHeight; double ratio = Math.min(wr, hr); float n = 1.0f; while ((n * 2) <= ratio) { n *= 2; } return (int) n; }
4.2、xutil的inSample的算法:
final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (width > maxWidth || height > maxHeight) { if (width > height) { inSampleSize = Math.round((float) height / (float) maxHeight); } else { inSampleSize = Math.round((float) width / (float) maxWidth); } final float totalPixels = width * height; final float maxTotalPixels = maxWidth * maxHeight * 2; while (totalPixels/ (inSampleSize * inSampleSize) > maxTotalPixels) { inSampleSize++; } } return ;
4.3、UIL(图片缓冲)的inSample的算法:
final int srcWidth = srcSize.getWidth(); final int srcHeight = srcSize.getHeight(); final int targetWidth = targetSize.getWidth(); final int targetHeight = targetSize.getHeight(); int scale = 1; switch (viewScaleType) { case FIT_INSIDE: if (powerOf2Scale) { final int halfWidth = srcWidth / 2; final int halfHeight = srcHeight / 2; while ((halfWidth / scale) > targetWidth || (halfHeight / scale) > targetHeight) { // || scale *= 2; } } else { scale = Math.max(srcWidth / targetWidth, srcHeight / targetHeight); // max } break; case CROP: if (powerOf2Scale) { final int halfWidth = srcWidth / 2; final int halfHeight = srcHeight / 2; while ((halfWidth / scale) > targetWidth && (halfHeight / scale) > targetHeight) { // && scale *= 2; } } else { scale = Math.min(srcWidth / targetWidth, srcHeight / targetHeight); // min } break; } if (scale < 1) { scale = 1; } scale = considerMaxTextureSize(srcWidth, srcHeight, scale, powerOf2Scale); return scale;
5、Volley中NetWorkImageView的使用
NetWorkImageView:显示网络图片的控件
核心API:setImageUrl(url , imageLoader);
5.1、ImageCache对象
图片内存缓冲核心: public Bitmap getBitmap(String url)
Public void putBitmap(String url, Bitmap bitMap)
5.2、四种引用级别
(1)强引用:平时使用的集合,比如ArrayList、HashMap、HashSet
特点:oom也不回收内存
(2)软引用:SoftReference,HashMap<String, SoftReference<Bitmap>>
特点:内存不足,回收对象
以前开发使用软引用缓冲图片:2.3之后,谷歌建议建议使用LruCache代替。
(3)虚引用:形同虚设
(4)弱引用:不使用
5.3、LruCache介绍
(1)LRU:least recently used,最近最少使用
(2)使用LinkedHashMap作为存储结构
new LinkedHashMap<K, V>(0, 0.75f, true):
第一个参数:初始化容器大小
第二个参数:负载因子,比如初始化容器大小16,负载因子0.75,16 * 0.75=12, 当容器有12个元素时,自动增长。
第三个参数:true代表按照最近访问顺序排序(LruCache选择LinkedHashMap的核心原因),false按照插入顺序排序。
5.4、对LruCache的总结
缓存图片都要用到lrucache,它会用到lru算法,表示最近最少使用(可以扯一扯操作系统的页面置换算法及其原理),谷歌从安卓2.3后不建议使用软引用,是因为软引用当内存不足时会回收内存,我们应该在内存不足的之前,能处理应用不让它占用过多的内存。
查看源码发现LruCache内部用的数据结构是LinkedHashMap。使用map集合的原因是因为要存储图片是url-bitmmap键值对形式储存。选择map集合中的LinkedHashMap是因为其构造函数第三个参数决定,因为第三个参数使用lru。
5.5、NetWorkImageView使用案例:
public class MainActivity extends Activity { private NetworkImageView netWorkImg; private NetworkImageView netWorkImg2; private String url; private MainActivity context; private ImageLoader imageLoader; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); netWorkImg = (NetworkImageView) findViewById(R.id.netWorkImg); netWorkImg2 = (NetworkImageView) findViewById(R.id.netWorkImg2); url = "http://192.168.0.112:8080/imgs/movie4.PNG"; context = this; } /**从网络获取图片*/ public void loadImgFromNet(View v) { RequestQueue queue = Volley.newRequestQueue(context); ImageCache imageCache = new MyImageCache(); imageLoader = new ImageLoader(queue, imageCache); netWorkImg.setImageUrl(url, imageLoader); } /**从网络内存缓冲图片*/ public void loadImgFromRamCache(View v) { netWorkImg2.setImageUrl(url, imageLoader); } public class MyImageCache implements ImageCache { private LruCache bitmapCache; @SuppressLint("NewApi") public MyImageCache() { int cacheSize = 4 * 1024 * 1024; // 缓冲图片最大占用空间 bitmapCache = new LruCache(cacheSize) { @SuppressLint("NewApi") protected int sizeOf(String key, Bitmap value) { return value.getByteCount()/1024/1024;//返回每张图片占用内存大小 } }; } //从缓冲中获取Bimap对象 @SuppressLint("NewApi") @Override public Bitmap getBitmap(String url) { return (Bitmap) bitmapCache.get(url); } @SuppressLint("NewApi") @SuppressWarnings("unchecked") @Override //从图片缓冲的内存 public void putBitmap(String url, Bitmap bitMap) { bitmapCache.put(url, bitMap); } } }
当activity销毁时,也应该取消网络访问,可在activity中的finish()方法中,取消网络访问。
HttpClient停止网络请求:
HttpClient.getConnectiontManager()
ClientConnectionManager.shutdown()停止访问网络
Volley取消网络
(1)RequestQueue.stop(),取消单个网络访问
(2)RequestQueue.cancleAll(tag)取消所有网络,
7、Volley中的ImageLoader(现在开发中都是用UIL)
可以用来显示网络图片
RequestQueue queue = Volley.newRequestQueue(this); ImageLoader imageLoader = new ImageLoader(queue , new MyImageCache()); String url = "http://192.168.199.238:8080/imgs/car5.PNG"; imageLoader.get(url, new ImageListener() { @Override public void onErrorResponse(VolleyError error) { Toast.makeText(MainActivity.this,error.getMessage(), 0).show(); } @Override public void onResponse(ImageContainer response, boolean isImmediate) { Bitmap bitmap = response.getBitmap(); mImageView.setImageBitmap(bitmap); } });