編輯:關於Android編程
Volley是一個封裝HttpUrlConnection和HttpClient的網絡通信框架,集AsyncHttpClient和Universal-Image-Loader的優點於了一身,既可以像AsyncHttpClient一樣非常簡單地進行HTTP通信,也可以像Universal-Image-Loader一樣輕松加載並緩存下載的圖片。Volley在性能方面也進行了大幅度的調整,它的設計目標就是進行數據量不大,但通信頻繁的網絡操作
,而對於大數據量的網絡操作,比如說下載文件等,Volley的表現就會比較糟糕。從下面這個簡單的實例來研究一下源碼。
RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);
StringRequest stringRequest = new StringRequest(http://www.baidu.com, new Response.Listener() {
@Override
public void onResponse(String s) {
tv.setText(s);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
mQueue.add(stringRequest);
RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);
首先看一下RequestQueue這個類:
public class RequestQueue {
private AtomicInteger mSequenceGenerator;
private final Map> mWaitingRequests;
private final Set mCurrentRequests;
private final PriorityBlockingQueue mCacheQueue;
private final PriorityBlockingQueue mNetworkQueue;
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
private final Cache mCache;
private final Network mNetwork;
private final ResponseDelivery mDelivery;
private NetworkDispatcher[] mDispatchers;
private CacheDispatcher mCacheDispatcher;
public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {
this.mSequenceGenerator = new AtomicInteger();
this.mWaitingRequests = new HashMap();
this.mCurrentRequests = new HashSet();
this.mCacheQueue = new PriorityBlockingQueue();
this.mNetworkQueue = new PriorityBlockingQueue();
this.mCache = cache;
this.mNetwork = network;
this.mDispatchers = new NetworkDispatcher[threadPoolSize];
this.mDelivery = delivery;
}
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
public RequestQueue(Cache cache, Network network) {
this(cache, network, 4);
}
...
}
從構造函數可知,mWaitingRequests、mCurrentRequests、mCacheQueue、mNetworkQueue是以組合形式實例化,後兩者是阻塞隊列;而mCache、mNetwork是以聚合形式注入;mDelivery默認也是組合形式new ExecutorDelivery(new Handler(Looper.getMainLooper())))
實例化。
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, (HttpStack)null);
}
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
File cacheDir = new File(context.getCacheDir(), volley);
String userAgent = volley/0;
try {
String network = context.getPackageName();
PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);
userAgent = network + / + queue.versionCode;
} catch (NameNotFoundException var6) {
;
}
if(stack == null) {
if(VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
BasicNetwork network1 = new BasicNetwork((HttpStack)stack);
RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);
queue1.start();
return queue1;
}
結合RequestQueue類可知,實例化的RequestQueue對象,注入了new DiskBasedCache(cacheDir)
和network1
,緩存方式默認是磁盤緩存,NetWork對象會根據系統版本,選用不同的Http通信方式。
public void start() {
this.stop();
this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
this.mCacheDispatcher.start();
for(int i = 0; i < this.mDispatchers.length; ++i) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
this.mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
CacheDispatcher和NetworkDispatcher都是繼承Thread類,所以這個方法生成一條緩存分發線程,和四條網絡線程。
CacheDispatcher類繼承Thread類,所有參數都是聚合形式注入,看下關鍵的run()方法,由於代碼較長,這裡不貼了,分段分析下幾個比較重要的方法
while(true){
...
Request e = (Request)this.mCacheQueue.take();
...
}
首先任務是一個死循環,由於mCacheQueue是個阻塞隊列,所以將不斷地從阻塞隊列讀取Request
Entry entry = this.mCache.get(e.getCacheKey());
if(entry == null) {
e.addMarker(cache-miss);
this.mNetworkQueue.put(e);
} else if(entry.isExpired()) {
e.addMarker(cache-hit-expired);
e.setCacheEntry(entry);
this.mNetworkQueue.put(e);
} else {
e.addMarker(cache-hit);
Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
...
}
判斷請求是否有緩存,如果沒有或者緩存已經過期,將請求放到網絡隊列裡面
。否則找到緩存,則進行下面的操作。
Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
parseNetworkResponse是Request類的抽象方法,我們進去StringRequest看下:
protected Response parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException var4) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
可看作是對網絡下載的數據進行解析處理,然後返回。
this.mDelivery.postResponse(e, response);
最後進行這一步,mDelivery是在RequestQueue裡面實例化後注入CacheDispatcher的,具體的實例化對象:new ExecutorDelivery(new Handler(Looper.getMainLooper()))。看下ExecutorDelivery類,找到postResponse方法。
public void postResponse(Request request, Response response) {
this.postResponse(request, response, (Runnable)null);
}
public void postResponse(Request request, Response response, Runnable runnable) {
...
this.mResponsePoster.execute(new ExecutorDelivery.ResponseDeliveryRunnable(request, response, runnable));
}
繼續往下看
private class ResponseDeliveryRunnable implements Runnable {
...
run(){
...
if(this.mResponse.isSuccess()) {
this.mRequest.deliverResponse(this.mResponse.result);
}
...
}
...
}
deliverResponse方法同樣是Request類的抽象方法,我們進去StringRequest看下
protected void deliverResponse(String response) {
this.mListener.onResponse(response);
}
就一句回調
1、從網絡阻塞隊列讀取請求,request = (Request)this.mQueue.take();
2、網絡下載,NetworkResponse e = this.mNetwork.performRequest(request);(如果是CacheDispatcher這一步就是緩存判斷)
3、處理下載後的數據,Response response = request.parseNetworkResponse(e);
3、對處理後的數據進行回調,this.mDelivery.postResponse(e, response)。
StringRequest stringRequest = new StringRequest (url,listener,errorListener);
public class StringRequest extends Request {
private final Listener mListener;
public StringRequest(int method, String url, Listener listener, ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
}
public StringRequest(String url, Listener listener, ErrorListener errorListener) {
this(0, url, listener, errorListener);
}
protected void deliverResponse(String response) {
this.mListener.onResponse(response);
}
protected Response parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException var4) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
}
由第一個分析步驟可以知道,這個Request主要就是進行兩個操作,也就是重寫兩個方法。
protected abstract Response parseNetworkResponse(NetworkResponse var1);
對下載後的數據進行解析處理; protected abstract void deliverResponse(T var1);
最後回調操作這個數據的方法。
所以構造函數僅需下載地址和回調操作的方法。
if(!request.shouldCache()) {
this.mNetworkQueue.add(request);
return request;
}
如果不需要緩存就直接添加到網絡隊列裡面,Request有個比較重要的布爾字段mShouldCache,默認是用來判斷是否要進行磁盤緩存的。
this.mCacheQueue.add(request);
否則將其添加到緩存隊列,這個方法上面也會進行一些當前隊列和等待隊列的防重復的操作。
框架部分:
1、實例化一個RequestQueue對象,開啟一條緩存線程和默認的四條網絡線程,線程不斷地從緩存阻塞隊列和網絡阻塞隊列裡面讀取請求;
2、如果緩存線程從緩存隊列裡面讀取的請求已經緩存過,則解析數據回調操作方法,否則將其添加到網絡隊列;
3、如果緩存線程從緩存隊列裡面讀取的請求沒有緩存過,則添加到網絡隊列。
4、網絡線程從網絡阻塞隊列不斷讀取請求,讀到請求後則由封裝好的HttpStack對象進行網絡下載處理、下載後回調對數據處理的方法,處理後回調操作數據的方法。
客戶部分:
1、實例化一個請求對象,在請求對象裡面重寫處理網絡下載後的數據的方法,和操作處理後的數據的方法。
2、將請求對象添加到請求隊列,請求需要緩存則會被添加到分配到緩存隊列,不需要則被添加到網絡隊列。
之前看過一個問題,說框架和庫有什麼不同,高人答曰:框架是他調用你代碼,庫是你調用他代碼。優秀的框架拓展性是如此之強,雖然自己遠沒那個能力,不過也算開了眼界!
之前一旦時間覺得不知道看些什麼學些什麼還打游戲,有點頹廢。然後想想總得繼續學習,正好I/O大會剛結束,那就來看一些新東西https://github.com/ddwhan
1、問題描述首先,需要解析的Json數據類似於下面的格式,但是包含了Java關鍵字abstract:{ ret: 0, msg: "
Android系統中的很多安全類軟件都支持垃圾清理,但總有一些不知名文件夾能逃過類似功能的“洗禮”。那麼,我們如何根據一些蛛絲馬跡了
有時候需要用到第三方API的時候,需要一個key store 的SH1值,例如使用百度地圖API,如果是協同開發,就需要所有Eclipse使用同一keystore。