一直想找个优秀的开源框架学习下,Volley非常合适,研究下来学到了不少知识
Volley简介
Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身,既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载网络上的图片。除了简单易用之外,Volley在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。
先解释一下,对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕,为什么呢? 因为我们知道对于大文件的下载,我们一般的处理方式是把网络输入流直接写入文件,不写入内存,这样有效防止OOM,但是Volley,并没有针对大文件下载做任何处理,还是通用的实现,先写入内存,然后写入硬盘缓存。
导入Volley库
Google官方的Volley
android studio中添加volley
So Volley has been updated to Android studio build style which makes it harder create a jar. But the recommended way for eclipse was using it as a library project and this goes for android studio as well, but when workgin in android studio we call this a module. So here is a guide to how do it the way Google wants us to do it. Guide is based on this nice tutorial.
- First get latest volley with git (git clone https://android.googlesource.com/platform/frameworks/volley).
- In your current project (android studio) click [file] –[Import Module].
- Now select the directory where you downloaded Volley to.
- Now Android studio might guide you to do the rest but continue guide to verify that everything works correct
- Open settings.gradle (find in root) and add (or verify this is included):
include ‘:app’, ‘:volley’- Now go to your build.gradle in your project and add the dependency:
compile project(“:volley”)
Thats all there is to it, much simpler and easier than compiling a jar and safer than relying on third parties jars or maven uploads.
另一个经常用的是 mcxiaoke/android-volley 这个非官方的volley项目优化了代码,据说解决了部分官方volley OOM的问题。后面会分析这个项目具体都解决了些什么问题。
- compile ‘com.mcxiaoke.volley:library:1.0.19-SNAPSHOT’
- 或者按照上面的方式,作为库项目添加到AS中
使用beyond compare
比较谷歌官方的volley和mcxiaoke/android-volley的区别
注意,因为两者格式不一样,所以不能通过文件的二进制格式比较,全选Compare Contents选择第三项,Rules-based compration按内容比较,那么就不会全线都飘红啦,可以很方便的知道那些文件修改过
最后发现其实没多大的区别,,,基本一样,所以使用哪个都可以
至于说会官方Volley会出现OOM那是很久以前的事了,现在不会。
CacheDispacher线程保持了context的引用,导致GC没有释放该Activity。可以看到现在最新的Volley的CacheDispacher并没有引用context,所以这个OOM是不会发生的
使用
这个就不多说了
想粗略的就参考这里吧 《Android Volley完全解析(一),初识Volley的基本用法》 一系列的文章
基本用法
注意以下地方
- mQueue只需要调用一次就行了Volley.newRequestQueue(this);这个方法内部会调用start方法,start方法默认开启1个缓存线程,4个网络请求线程。如果new多次了,那么系统资源肯定最后要被耗尽啊。
- mQueue如果能设置为单例的就最好不过了,就不用频繁的去创建销毁线程了,占用系统资源。Volley内部并没有使用线程池来管理缓存线程和网络请求线程。
- 如果mQueue没有设置为单例模式,那么onDestroy方法必须调用RequestQueue的stop方法,停止缓存线程和网络请求线程。这两个线程内部实现都是while无线循环的,除非调用了stop方法才退出while。想象一下,如果没有stop,那么启动一个activity,如果要做网络请求,那么就new一个RequestQueue,就是创建5个线程出来,但是没有去停止这几个线程,所以一直累积累积,最后后果不堪设想。
public class MainActivity extends AppCompatActivity {
private RequestQueue mQueue;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
mQueue = Volley.newRequestQueue(this);
}
@OnClick(R.id.but)
void onClick() {
StringRequest stringRequest = new StringRequest("http://www.baidu.com",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
QDLog.d("onResponse:" + response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
QDLog.d("onErrorResponse: " + error.getMessage());
}
});
mQueue.add(stringRequest);
}
@Override
protected void onDestroy() {
super.onDestroy();
mQueue.stop();
}
}
post方法添加请求参数,重写StringRequest的getParams
StringRequest stringRequest = new StringRequest(Method.POST, url, listener, errorListener) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> map = new HashMap<String, String>();
map.put("params1", "value1");
map.put("params2", "value2");
return map;
}
};
加载网络图片
提供了三种方式
1. ImageRequest
ImageRequest继承自Request,所以跟StringRequest等的使用方法差不多,提供了硬盘缓存,同时为了防止OOM对原图片进行了缩放处理。但是另一个问题,ImageRequest不适用于listview,gridview等滑动快速,需要频繁加载图片的场景,因为没有提供内存缓存。这个时候就需要使用ImageLoader咯,相比较ImageRequest,多了内存缓存的功能实现
2. ImageLoader
内部还是采用ImageRequest来实现的,只是添加了一级缓存(内存缓存)而已
下面的系列会介绍ImageRequest和ImageLoader的区别和联系
3. NetworkImageView
这个就不说了,NetworkImageView是一个自定义View,它是继承自ImageView的,具备ImageView控件的所有功能,并且在原生的基础之上加入了加载网络图片的功能
自定义Request
必须实现parseNetworkResponse
(解析网络请求结果)和deliverResponse
(分发结果)这两个方法
public class GsonRequest<T> extends Request<T> {
private final Listener<T> mListener;
private Gson mGson;
private Class<T> mClass;
public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener,
ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
mClass = clazz;
mListener = listener;
}
public GsonRequest(String url, Class<T> clazz, Listener<T> listener,
ErrorListener errorListener) {
this(Method.GET, url, clazz, listener, errorListener);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(mGson.fromJson(jsonString, mClass),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
}