一直想找個優秀的開源框架學習下,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);
}
}