編輯:關於Android編程
async-http使用地址
android-async-http倉庫:git clonehttps://github.com/loopj/android-async-http
源碼分析
我們在做網絡請求的時候經常通過下面的方式實例化AsyncHttpClient client=new AsyncHttpClient();然後通過系統內置的請求發送請求,通過async內部的請求去做真正的網絡請求。
首先得到的是AsyncHttpClient實例,所以從這裡入手分析一下:
/**
* Creates a new AsyncHttpClient with default constructor arguments values
*/
public AsyncHttpClient() {
this(false, 80, 443);
}
對於默認值設置了HTTP協議的默認端口為80,HTTPS協議的默認端口為443。
在該函數中調用了AsyncHttpClient(SchemeRegistry schemeRegistry)
構造函數,而真正的實例化獲取邏輯過程就在AsyncHttpClient(SchemeRegistry schemeRegistry)
方法中,如下所示:
/**
* Creates a new AsyncHttpClient.
*
* @param schemeRegistry SchemeRegistry to be used
*/
public AsyncHttpClient(SchemeRegistry schemeRegistry) {
BasicHttpParams httpParams = new BasicHttpParams();
ConnManagerParams.setTimeout(httpParams, connectTimeout);
ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(maxConnections));
ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);
HttpConnectionParams.setSoTimeout(httpParams, responseTimeout);
HttpConnectionParams.setConnectionTimeout(httpParams, connectTimeout);
HttpConnectionParams.setTcpNoDelay(httpParams, true);
HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE);
HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
ClientConnectionManager cm = createConnectionManager(schemeRegistry, httpParams);
Utils.asserts(cm != null, "Custom implementation of #createConnectionManager(SchemeRegistry, BasicHttpParams) returned null");
threadPool = getDefaultThreadPool();
requestMap = Collections.synchronizedMap(new WeakHashMap>());
clientHeaderMap = new HashMap();
httpContext = new SyncBasicHttpContext(new BasicHttpContext());
httpClient = new DefaultHttpClient(cm, httpParams);
httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
@Override
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()) {
if (request.containsHeader(header)) {
Header overwritten = request.getFirstHeader(header);
Log.d(LOG_TAG,
String.format("Headers were overwritten! (%s | %s) overwrites (%s | %s)",
header, clientHeaderMap.get(header),
overwritten.getName(), overwritten.getValue())
);
//remove the overwritten header
request.removeHeader(overwritten);
}
request.addHeader(header, clientHeaderMap.get(header));
}
}
});
httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
@Override
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(entity));
break;
}
}
}
}
});
httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
@Override
public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(
ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
if (authState.getAuthScheme() == null) {
AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort());
Credentials creds = credsProvider.getCredentials(authScope);
if (creds != null) {
authState.setAuthScheme(new BasicScheme());
authState.setCredentials(creds);
}
}
}
}, 0);
httpClient.setHttpRequestRetryHandler(new RetryHandler(DEFAULT_MAX_RETRIES, DEFAULT_RETRY_SLEEP_TIME_MILLIS));
}
從代碼的最頂層分析,構造參數傳入的是SchemeRegistry對象,查看源碼這是一個靜態的方法,主要存儲一些協議的東西
public SchemeRegistry() {
super();
registeredSchemes = new ConcurrentHashMap
}
上面的代碼我們主要關注下addResponseInterceptor和addResponseInterceptor,此兩個方法主要將我們的請求頭和請求的實體加到HttpRequest隊列中,對android1.5之前的熟悉的朋友都知道,在最早之前沒有流行這些第三方之前我們就是通過HttpRequest來請求的,這等同於j2ee的HttpServletRequest.
接下來我們調運的就是AsyncHttpClient裡面的各種get、post、delete等方法,通過看代碼可以發現它們最終調用的都是sendRequest方法,如下:
/**
* Puts a new request in queue as a new thread in pool to be executed
*
* @param client HttpClient to be used for request, can differ in single requests
* @param contentType MIME body type, for POST and PUT requests, may be null
* @param context Context of Android application, to hold the reference of request
* @param httpContext HttpContext in which the request will be executed
* @param responseHandler ResponseHandler or its subclass to put the response into
* @param uriRequest instance of HttpUriRequest, which means it must be of HttpDelete,
* HttpPost, HttpGet, HttpPut, etc.
* @return RequestHandle of future request process
*/
protected RequestHandle sendRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, ResponseHandlerInterface responseHandler, Context context) {
if (uriRequest == null) {
throw new IllegalArgumentException("HttpUriRequest must not be null");
}
if (responseHandler == null) {
throw new IllegalArgumentException("ResponseHandler must not be null");
}
if (responseHandler.getUseSynchronousMode() && !responseHandler.getUsePoolThread()) {
throw new IllegalArgumentException("Synchronous ResponseHandler used in AsyncHttpClient. You should create your response handler in a looper thread or use SyncHttpClient instead.");
}
if (contentType != null) {
if (uriRequest instanceof HttpEntityEnclosingRequestBase && ((HttpEntityEnclosingRequestBase) uriRequest).getEntity() != null) {
Log.w(LOG_TAG, "Passed contentType will be ignored because HttpEntity sets content type");
} else {
uriRequest.setHeader(HEADER_CONTENT_TYPE, contentType);
}
}
responseHandler.setRequestHeaders(uriRequest.getAllHeaders());
responseHandler.setRequestURI(uriRequest.getURI());
AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context);
threadPool.submit(request);
RequestHandle requestHandle = new RequestHandle(request);
if (context != null) {
// Add request to request map
List requestList = requestMap.get(context);
synchronized (requestMap) {
if (requestList == null) {
requestList = Collections.synchronizedList(new LinkedList());
requestMap.put(context, requestList);
}
}
requestList.add(requestHandle);
Iterator iterator = requestList.iterator();
while (iterator.hasNext()) {
if (iterator.next().shouldBeGarbageCollected()) {
iterator.remove();
}
}
}
return requestHandle;
}
這個方法的主要作用是將一個新的請求添加到隊列線程池中執行。
調用本方法,主要實現AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest,contentType, responseHandler, context);
這行開始是主要的邏輯,其創建了請求,接著通過threadPool.submit(request);
把請求提交到線程池,接著通過RequestHandle requestHandle = new RequestHandle(request);
把請求包裝到RequestHandle用於之後的取消、管理等操作。然後坐等現在池的我們請求的這個線程去執行,等待返回結果。
總結一下:
AsyncHttpClient 核心類,使用HttpClient執行網絡請求,提供了get,put,post,delete,head等請求方法,使用起來很簡單,只需以url及RequestParams調用相應的方法即可,還可以選擇性地傳入Context,用於取消Content相關的請求,同時必須提供ResponseHandlerInterface(AsyncHttpResponseHandler繼承自ResponseHandlerInterface)的實現類,一般為AsyncHttpResponseHandler的子類,AsyncHttpClient內部有一個線程池,當使用AsyncHttpClient執行網絡請求時,最終都會調用sendRequest方法,在這個方法內部將請求參數封裝成AsyncHttpRequest(繼承自Runnable)交由內部的線程池執行。
SyncHttpClient 繼承自AsyncHttpClient,同步執行網絡請求,AsyncHttpClient把請求封裝成AsyncHttpRequest後提交至線程池,SyncHttpClient把請求封裝成AsyncHttpRequest後直接調用它的run方法。
AsyncHttpRequest 繼承自Runnabler,被submit至線程池執行網絡請求並發送start,success等消息。
AsyncHttpResponseHandler 接收請求結果,一般重寫onSuccess及onFailure接收請求成功或失敗的消息,還有onStart,onFinish等消息。
TextHttpResponseHandler、JsonHttpResponseHandler、BaseJsonHttpResponseHandler這些類都繼承自AsyncHttpResponseHandler,只是重寫了AsyncHttpResponseHandler的onSuccess和onFailure方法,將請求結果進行了轉換而已。
RequestParams 請求參數,可以添加普通的字符串參數,並可添加File,InputStream上傳文件。
““XXX(機主姓名)看這個,ht://********XXshenqi.apk”最近一種手機病毒爆發,機主收到這樣的短信,開頭是以發
上篇分析AsyncTask的一些基本用法以及不同android版本下的區別,接著本篇我們就來全面剖析一下AsyncTask的工作原理。在開始之前我們先來了解一個多線程的知
DatePicker實戰效果圖:依賴導入compile 'cn.aigestudio.datepicker:DatePicker:2.2.0'DatePi
RecycleView出來已經有一兩個年頭了最近在項目中完全替換掉了ListView很有必要的寫一篇記錄一下使用過程,以便以後溫故而知新。RecycleView的使用場景