---恢復內容開始---
還是繼續FinalHttp,這個類涉及到的東西還是挺多的。
一:線程池
首先我們看到FinalHttp類里面有兩個跟線程池相關的兩個靜態類
private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); public Thread newThread(Runnable r) { Thread tread = new Thread(r, "FinalHttp #" + mCount.getAndIncrement()); tread.setPriority(Thread.NORM_PRIORITY - 1); return tread; } }; private static final Executor executor =Executors.newFixedThreadPool(httpThreadCount, sThreadFactory);
ThreadFactory是一個工廠模式,下面是一個線程池Executor。線程池里new出來的線程都是這個ThreadFactory孵化出來的線程,賦予了原始信息線程名字都是FinalHttp #n,(這里還有一個AtomicInteger,這是一個原子操作類,主要用於在高並發環境下的高效程序處理。使用非阻塞算法來實現並發控制。)並且設置線程優先級。
看到這個類里面很多方法都有傳遞這個Executor線程池,沒到執行一個線程我想都是executor 加入線程池去執行的,這樣的線程管理是比較高效和出色的。
二:構造方法
這個構造方法有超多默認配置,蛋疼了米有?
public FinalHttp() { BasicHttpParams httpParams = new BasicHttpParams(); ConnManagerParams.setTimeout(httpParams, socketTimeout); ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(maxConnections)); ConnManagerParams.setMaxTotalConnections(httpParams, 10); HttpConnectionParams.setSoTimeout(httpParams, socketTimeout); HttpConnectionParams.setConnectionTimeout(httpParams, socketTimeout); HttpConnectionParams.setTcpNoDelay(httpParams, true); HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE); HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1); SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(httpParams, schemeRegistry); httpContext = new SyncBasicHttpContext(new BasicHttpContext()); httpClient = new DefaultHttpClient(cm, httpParams); httpClient.addRequestInterceptor(new HttpRequestInterceptor() { public void process(HttpRequest request, HttpContext context) { if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) { request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP); } for (String header : clientHeaderMap.keySet()) { request.addHeader(header, clientHeaderMap.get(header)); } } }); httpClient.addResponseInterceptor(new HttpResponseInterceptor() { public void process(HttpResponse response, HttpContext context) { final HttpEntity entity = response.getEntity(); if (entity == null) { return; } final Header encoding = entity.getContentEncoding(); if (encoding != null) { for (HeaderElement element : encoding.getElements()) { if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) { response.setEntity(new InflatingEntity(response.getEntity())); break; } } } } }); httpClient.setHttpRequestRetryHandler(new RetryHandler(maxRetries)); clientHeaderMap = new HashMap<String, String>(); }
httpParams是一個網絡鏈接配置類,比如設置最大連接數,路由最大連接數,讀取超時時間,連接超時時間,套接字緩沖大小。這里連接數都是10次,超市時間都是10秒,其實這樣本來就是一種網絡請求任務的拖慢。再下面還有個重復次數,竟然是5次,如果網絡不好的話有可能要重試5次,這樣嚴重影響了上層的UI交互。不過有個亮點就是g-zip,Gzip開啟以后會將輸出的數據進行壓縮的處理,這樣就會減小通過網絡傳輸的數據量,提高讀取的速度。
三:AfinalHttp里的方法
1.配置方法:
public void configCharset(String charSet){ if(charSet!=null && charSet.trim().length()!=0) this.charset = charSet; } public void configCookieStore(CookieStore cookieStore) { httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); } public void configUserAgent(String userAgent) { HttpProtocolParams.setUserAgent(this.httpClient.getParams(), userAgent); } /** * 設置網絡連接超時時間,默認為10秒鍾 * @param timeout */ public void configTimeout(int timeout){ final HttpParams httpParams = this.httpClient.getParams(); ConnManagerParams.setTimeout(httpParams, timeout); HttpConnectionParams.setSoTimeout(httpParams, timeout); HttpConnectionParams.setConnectionTimeout(httpParams, timeout); } /** * 設置https請求時 的 SSLSocketFactory * @param sslSocketFactory */ public void configSSLSocketFactory(SSLSocketFactory sslSocketFactory) { Scheme scheme = new Scheme("https", sslSocketFactory, 443); this.httpClient.getConnectionManager().getSchemeRegistry().register(scheme); } /** * 配置錯誤重試次數 * @param retry */ public void configRequestExecutionRetryCount(int count){ this.httpClient.setHttpRequestRetryHandler(new RetryHandler(count)); }
這些配置應該都在發起請求之前執行,不過設置超時這個方法太狗血了,竟然三種超時都是10s,那是不是意味着有可能3種超時加起來就要30s,半分鍾啊!
2.請求方法入口,有常用的get()方法,post()方法,download()文件下載方法得各種重載。
那些重載方法這就不貼了,都是調用的HttpHandler類去處理的。
這里我們看到有幾個東西:
AjaxParams,這是一個設置url參數的類。
筆者在實際使用過程中發現,有兩個缺陷。
一個是里頭用到的是ConcurrentHashMap,我們看一看java中幾種常用集合的對比。
Map
HashMap 無序
HashTable:線程安全
LinkedHashMap 有序
ConcurrentHashMap 無序 線程安全
TreeMap:重新排序
ConcurrentHashMap 是線程安全的,但卻是無序的。適用於高並發情景,但是無序在此就不太恰當。比如有個www.bvin.com/login.jsp?name=bvin&pw=888888,如果用這個Ajax去Put進去的話,有可能會出現像這樣的情況:www.bvin.com/login.jsp?pw=888888&name=bvin,明顯這樣是錯誤的。
還有一點就是,這個類竟然沒有clean()或者removeAll()方法。如果要再次用到這個類的話,就必須重新new一個。其實寫這么個方法就舉手投足的事,AjaxParams里面其實就是兩個ConcurrentHashMap實例。只要把下面這兩個清空就行了。
protected ConcurrentHashMap<String, String> urlParams;
protected ConcurrentHashMap<String, FileWrapper> fileParams;
AjaxCallBack,這是一個泛型抽象類,起回調作用。
public void onStart(){}; public void onLoading(long count,long current){}; public void onSuccess(T t){}; public void onFailure(Throwable t,String strMsg){};
3.發送請求方法
protected <T> void sendRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, AjaxCallBack<T> ajaxCallBack) { if(contentType != null) { uriRequest.addHeader("Content-Type", contentType); } new HttpHandler<T>(client, httpContext, ajaxCallBack,charset) .executeOnExecutor(executor, uriRequest); } protected Object sendSyncRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType) { if(contentType != null) { uriRequest.addHeader("Content-Type", contentType); } return new SyncRequestHandler(client, httpContext,charset).sendRequest(uriRequest); }
這里涉及到HttpHandler和SyncRequestHandler兩各類,下回分解了。。。