一、前言:
Volley是Google官方出的一套小而巧的异步请求库,该框架封装的扩展性很强,支持HttpClient、HttpUrlConnection,甚至支持OkHttp,而且Volley里面也封装了ImageLoader,所以如果你愿意你甚至不需要使用图片加载框架,不过这块功能没有一些专门的图片加载框架强大,对于简单的需求可以使用,对于稍复杂点的需求还是需要用到专门的图片加载框架。
Volley也有缺陷,比如不支持post大数据,所以不适合上传文件。不过Volley设计的初衷本身也就是为频繁的、数据量小的网络请求而生!
1. Volley网络请求队列
Volley 请求网络都是基于请求队列的,开发者只要把请求放在请求队列中就可以了,请求队列会依次进行请求。一般情况下,一个应用程序如果网络请求不是特别的频繁,完全可以只有一个请求队列(对应 Application);如果网络请求非常多或者有其他情况,则可以是一个 Activity 对应一个网络请求队列,这就要看具体情况了。
示例:
RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
网络请求权限一定不要忘记:
二、 基本使用:
1.volley依赖
//volley依赖
implementation 'com.mcxiaoke.volley:library:1.0.19'
//gson依赖
compile 'com.google.code.gson:gson:2.7'
//butterknife,配置下面 两行
implementation 'com.jakewharton:butterknife:8.5.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
2.RequestQueue在 Application 中初始化一次
public class MyApplication extends Application {
public static RequestQueue queue;
@Override
public void onCreate() {
super.onCreate();
queue = Volley.newRequestQueue(getApplicationContext());
}
/**
* 提供全局变量,如果使用 VolleyUtils 类,这里就不用写了
* 创建请求队列对象,通常情况下,一个类中(或者说一个工程中)保持 始终使用同一个RequestQueue对象即可
* @return
*/
public static RequestQueue getHttpQueues() {
return queue;
}
}
3. StringRequest 中GET 请求
/**
* get 请求
*/
private void getRequest() {
String url = "http://apis.juhe.cn/mobile/get?phone=18856907654&key=5778e9d9cf089fc3b093b162036fc0e1";
/**
* 1. int 类型 用于指定请求的方式(如GET或者POST)
* 2. String类型 用于指定网络请求要连接的网址
* 3. Listener类型 ,接收网络响应的接口,即只要得到本次请求对应的返回结果
* 就会运行此接口中的onResponse方法
* 4: ErrorListener类型, 用于接收当网络请求的过程中一旦发生了什么错误,
* 就会调用本接口中的onErrorResponse方法
* */
StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, url, new Response.Listener() {
@Override
public void onResponse(String response) {
Log.d("LUO", "========" + response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d("LUO", "========" + error.getMessage());
}
});
//三,给请求对象设置tag标识
stringRequest.setTag("get");
//四,将请求添加到请求队列中,执行网络请求
MyApplication.getHttpQueues().add(stringRequest);
//不要调用,看下方注意
//MyApplication.getHttpQueues().start();
}
注意:
//MyApplication.getHttpQueues().start();
建议不要手动调用 RequestQueue 的 start() 方法,引起的问题“经常会报com.android.volley.NoConnectionError: java.io.InterruptedIOException”,然后就内容加载失败。。。
因为在 Volley.newRequestQueue() 方法中,已经调用了 start() 方法。
看源码示例:
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
Network network = new BasicNetwork(stack);
RequestQueue queue;
if (maxDiskCacheBytes <= -1)
{
// No maximum size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
}
else
{
// Disk cache size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
}
//这里已经启动了,不需要请求中再次调用
queue.start();
return queue;
}
3. StringRequest 中 POST请求
/**
* post 请求
*/
private void postRequest() {
RequestQueue queue = Volley.newRequestQueue(this);
String postUrl = "http://apis.juhe.cn/mobile/get";
StringRequest stringRequest = new StringRequest(StringRequest.Method.POST, postUrl, new Response.Listener() {
@Override
public void onResponse(String response) {
Log.d("LUO", "========" + response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d("LUO", "========" + error.getMessage());
}
}) {
/**
* Post请求和Get请求的使用步骤上的区别在于请求条件的指定
* 必须在StringRequest对象的后面添加{},并且
* 在{}内重写getParams方法,该方法的返回值就是所有的请求条件
* */
@Override
protected Map getParams() throws AuthFailureError {
//将请求条件封装到map对象中
Map map = new HashMap<>();
map.put("phone", "18856907654");
map.put("key", "5778e9d9cf089fc3b093b162036fc0e1");
return map;
}
};
//三,给请求对象设置tag标识
stringRequest.setTag("get");
//四,将请求添加到请求队列中,执行网络请求
MyApplication.getHttpQueues().add(stringRequest);
}
4.JSONObject网络请求
private void jsonRequest() {
String postUrl = "http://apis.juhe.cn/mobile/get";
Map map = new HashMap<>();
map.put("phone", "18856907654");
map.put("key", "5778e9d9cf089fc3b093b162036fc0e1");
String json = new Gson().toJson(map);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST,
postUrl,json, new Response.Listener() {
@Override
public void onResponse(JSONObject response) {
Log.d("LUO", "========" + response);
}
},new Response.ErrorListener(){
@Override
public void onErrorResponse(VolleyError error) {
Log.d("LUO", "========" + error.getMessage());
}
});
MyApplication.getHttpQueues().add(jsonObjectRequest);
}
5.下载单张图片
/**
* 下载单张图片
*/
private void singlePhoto() {
ImageRequest imageRequest = new ImageRequest(
"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2019270811,1269730008&fm=27&gp=0.jpg", //对应图片的下载地址
new Response.Listener() {
@Override
public void onResponse(Bitmap response) {
Log.d("LUO", "========" + response);
ivIcon.setImageBitmap(response);
}
}, 200, 200,// 指定下载后图片的最大宽高
ImageView.ScaleType.FIT_XY,//指定图片的缩放模式
Bitmap.Config.ARGB_8888,//指定图片的编码格式
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d("LUO", "========" + error.getMessage());
}
});
MyApplication.getHttpQueues().add(imageRequest);
}
6.与Avctivity生命周期联动(注意啊)
其实就是在Activity退出时候或销毁时候,取消对应的网络请求,避免网络请求在后台浪费资源,所以,我们一般在onStop()方法中通过之前设置的Tag取消网络请求:
@Override
protected void onDestroy() {
super.onDestroy();
//通过Tag标签取消请求队列中对应的全部请求
MyApplication.getHttpQueues().cancelAll(tag);
}
三、封装使用:
1.VolleyUtils类
public class VolleyUtils {
private static RequestQueue mQueue;
private ImageLoader mLoader;
private ImageLoader.ImageCache mCache;
private static VolleyUtils mInstance;
/**
* 1.构造方法私有化
* @param context
*/
private VolleyUtils(Context context) {
//做一些事情
mQueue = Volley.newRequestQueue(context);
mCache = new MyImageCache();
mLoader = new ImageLoader(mQueue, mCache);
}
public RequestQueue getQueue() {
return mQueue;
}
public ImageLoader getLoader() {
return mLoader;
}
/**
* 2.提供一个静态方法,返回一个当前类
* @param context
* @return
*/
public static VolleyUtils create(Context context) {
if (mInstance == null) {
synchronized (VolleyUtils.class) {
if (mInstance == null) {
mInstance = new VolleyUtils(context);
}
}
}
return mInstance;
}
public void get(String url, final Class clazz, final OnResponse listener) {
HashMap map = new HashMap<>();
listener.OnMap(map);
String param = prepareParam(map);
if (param.trim().length() >= 1) {
url += "?" + param;
}
Log.e("Volley", "urlResult---->" + url);
StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, url, new Response.Listener() {
@Override
public void onResponse(String response) {
Log.e("Volley", "response-->" + response);
Gson gson = new Gson();
listener.onSuccess(gson.fromJson(response, clazz));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("Volley", "response-->" + error.getMessage());
listener.onError(error.getMessage());
}
});
mQueue.add(stringRequest);
}
private static String prepareParam(Map paramMap) {
StringBuilder sb = new StringBuilder();
if (paramMap.isEmpty()) {
return "";
} else {
for (String key : paramMap.keySet()) {
String value = paramMap.get(key);
if (sb.length() < 1) {
sb.append(key).append("=").append(value);
} else {
sb.append("&").append(key).append("=").append(value);
}
}
return sb.toString();
}
}
public void post(String url, final Class clazz, final OnResponse listener) {
StringRequest stringRequest = new StringRequest(StringRequest.Method.POST, url, new Response.Listener() {
@Override
public void onResponse(String response) {
Log.e("Volley", "response-->" + response);
Gson gson = new Gson();
listener.onSuccess(gson.fromJson(response, clazz));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("Volley", "response-->" + error.getMessage());
listener.onError(error.getMessage());
}
}) {
/**
* Post请求和Get请求的使用步骤上的区别在于请求条件的指定
* 必须在StringRequest对象的后面添加{},并且
* 在{}内重写getParams方法,该方法的返回值就是所有的请求条件
* */
@Override
protected Map getParams() throws AuthFailureError {
//将请求条件封装到map对象中
Map map = new HashMap<>();
listener.OnMap(map);
return map;
}
};
mQueue.add(stringRequest);
}
public void loadImg(String url, ImageView view, int maxWidth, int maxHeight, int defaultImageResId, int errorImageResId) {
mLoader.get(url, //图片的下载路径
/**
* 通过getImageListener方法获取ImageListener接口对象
* 参数1: 图片下载完成后,由哪个控件显示图片
* 参数2: 设置图片下载过程中显示的默认图片
* 参数3: 设置一旦图片下载出错,就显示出错提示图片
* */
ImageLoader.getImageListener(view, defaultImageResId, errorImageResId),
maxWidth, maxHeight, //图片的最大宽高 指定成0的话就表示不管图片有多大
ImageView.ScaleType.FIT_XY //图片的缩放模式
);
}
public void loadImg(String url, ImageView view) {
mLoader.get(url, //图片的下载路径
ImageLoader.getImageListener(view, R.mipmap.ic_launcher, R.mipmap.ic_launcher),
0, 0, //图片的最大宽高 指定成0的话就表示不管图片有多大
ImageView.ScaleType.FIT_XY //图片的缩放模式
);
}
public void loadImg(String url, ImageView view, int defaultImageResId, int errorImageResId) {
mLoader.get(url, //图片的下载路径
ImageLoader.getImageListener(view, defaultImageResId, errorImageResId),
0, 0, //图片的最大宽高 指定成0的话就表示不管图片有多大
ImageView.ScaleType.FIT_XY //图片的缩放模式
);
}
/**
* 分配一定内存空间,专门存取图片,一般为内存大小的1/8
*/
private class MyImageCache implements ImageLoader.ImageCache {
private LruCache mCache;
private MyImageCache() {
//分配最大内存空间的1/8
long maxMemory = Runtime.getRuntime().maxMemory() / 8;
mCache = new LruCache((int) maxMemory) {
@Override
protected int sizeOf(String key, Bitmap value) {
//得到当前图片的大小
return value.getByteCount();
}
};
}
@Override
public Bitmap getBitmap(String url) {
return mCache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
if (getBitmap(url) == null)
mCache.put(url, bitmap);
}
}
/**
* 自定义的类型
* @param
*/
public class GsonRequest extends Request {
private Response.Listener mListener;
private Gson mGson;
private Class mClazz;
private GsonRequest(int method, String url, Response.Listener listener, Response.ErrorListener errorListenerlistener, Class clazz) {
super(method, url, errorListenerlistener);
this.mListener = listener;
mGson = new Gson();
this.mClazz = clazz;
}
@Override
protected Response parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
Log.e("Volley", "服务器返回JSON------>" + parsed);
return Response.success(mGson.fromJson(parsed, mClazz), HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new VolleyError(e));
}
}
@Override
protected void deliverResponse(T response) {
if (mListener != null) {
mListener.onResponse(response);
}
}
@Override
protected void onFinish() {
super.onFinish();
mListener = null;
}
}
public interface OnResponse {
void OnMap(Map map);
void onSuccess(T response);
void onError(String error);
}
}
2.PhoneBean类
public class PhoneBean {
/**
* resultcode : 200
* reason : Return Successd!
* result : {"province":"安徽","city":"合肥","areacode":"0551","zip":"230000","company":"移动","card":""}
* error_code : 0
*/
private String resultcode;
private String reason;
private ResultBean result;
private int error_code;
public String getResultcode() {
return resultcode;
}
public void setResultcode(String resultcode) {
this.resultcode = resultcode;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public ResultBean getResult() {
return result;
}
public void setResult(ResultBean result) {
this.result = result;
}
public int getError_code() {
return error_code;
}
public void setError_code(int error_code) {
this.error_code = error_code;
}
public static class ResultBean {
/**
* province : 安徽
* city : 合肥
* areacode : 0551
* zip : 230000
* company : 移动
* card :
*/
private String province;
private String city;
private String areacode;
private String zip;
private String company;
private String card;
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getAreacode() {
return areacode;
}
public void setAreacode(String areacode) {
this.areacode = areacode;
}
public String getZip() {
return zip;
}
public void setZip(String zip) {
this.zip = zip;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getCard() {
return card;
}
public void setCard(String card) {
this.card = card;
}
}
}
3.直接调用:
public class TwoActivity extends Activity{
private ImageView img;
String urlStr = "http://apis.juhe.cn/mobile/get";
String imgUrl = "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1263067444,118499721&fm=27&gp=0.jpg";
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two);
img = findViewById(R.id.img);
textView = findViewById(R.id.text);
}
public void btnGet(View view) {
VolleyUtils.create(this)
.get(urlStr, PhoneBean.class, new VolleyUtils.OnResponse() {
@Override
public void OnMap(Map map) {
map.put("phone", "18856907654");
map.put("key", "5778e9d9cf089fc3b093b162036fc0e1");
}
@Override
public void onSuccess(PhoneBean response) {
Log.e("TAG", "response---->" + response);
textView.setText("get :" + response.getResultcode() + " " + response.getResult().getCity());
}
@Override
public void onError(String error) {
Log.e("TAG", "error---->" + error);
textView.setText("error--->" + error);
}
});
}
public void btnPost(View view) {
VolleyUtils.create(this)
.post(urlStr, PhoneBean.class, new VolleyUtils.OnResponse() {
@Override
public void OnMap(Map map) {
map.put("phone", "18856907654");
map.put("key", "5778e9d9cf089fc3b093b162036fc0e1");
}
@Override
public void onSuccess(PhoneBean response) {
Log.e("TAG", "response---->" + response);
textView.setText("post :" + response.getResultcode() + " " + response.getResult().getCity());
}
@Override
public void onError(String error) {
Log.e("TAG", "error---->" + error);
textView.setText("error--->" + error);
}
});
}
public void btnImg(View view) {
VolleyUtils.create(this)
.loadImg(imgUrl, img);
// VolleyUtils.create(this)
// .loadImg(imgUrl,img,200,200,R.mipmap.ic_launcher,R.mipmap.ic_launcher);
//
// VolleyUtils.create(this)
// .loadImg(imgUrl,img,R.mipmap.ic_launcher,R.mipmap.ic_launcher);
}
public static void launch(Context mContext) {
Intent intent = new Intent(mContext,TwoActivity.class);
mContext.startActivity(intent);
}
}
GitHub地址:
-
- 展示代码的地址:https://github.com/lyyRunning/VolleyUtils
2.支持 HTTPS请求的地址:https://github.com/lyyRunning/VolleySSL
3.备用地址:https://github.com/guozhengXia/OkHttpUtils