zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

android-async-http框架源码分析

2023-09-14 08:58:01 时间
p span >async-http使用地址

android-async-http仓库:git clone https://github.com/loopj/android-async-http

源码分析

我们在做网络请求的时候经常通过下面的方式实例化AsyncHttpClient client=new AsyncHttpClient();然后通过系统内置的请求发送请求,通过async内部的请求去做真正的网络请求。

首先得到的是AsyncHttpClient实例,所以从这里入手分析一下:

 code style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: Source Code Pro, monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;" span /**

 * Creates a new AsyncHttpClient with default constructor arguments values

 */ /span 

 span public /span span AsyncHttpClient /span () {

 span this /span ( span false /span , span 80 /span , span 443 /span 

 } /code ul li 1 /li li 2 /li li 3 /li li 4 /li li 5 /li li 6 /li /ul 
对于默认值设置了HTTP协议的默认端口为80,HTTPS协议的默认端口为443。

在该函数中调用了AsyncHttpClient(SchemeRegistry schemeRegistry)构造函数,而真正的实例化获取逻辑过程就在AsyncHttpClient(SchemeRegistry schemeRegistry)方法中,如下所示:

 code style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: Source Code Pro, monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;" span /**

 * Creates a new AsyncHttpClient.

 * span @param /span schemeRegistry SchemeRegistry to be used

 */ /span 

 span public /span span AsyncHttpClient /span (SchemeRegistry schemeRegistry) {

 BasicHttpParams httpParams = span new /span BasicHttpParams();

 ConnManagerParams.setTimeout(httpParams, connectTimeout);

 ConnManagerParams.setMaxConnectionsPerRoute(httpParams, span new /span ConnPerRouteBean(maxConnections));

 ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);

 HttpConnectionParams.setSoTimeout(httpParams, responseTimeout);

 HttpConnectionParams.setConnectionTimeout(httpParams, connectTimeout);

 HttpConnectionParams.setTcpNoDelay(httpParams, span true /span 

 HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE);

 HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);

 ClientConnectionManager cm = createConnectionManager(schemeRegistry, httpParams);

 Utils.asserts(cm != span null /span , span "Custom implementation of #createConnectionManager(SchemeRegistry, BasicHttpParams) returned null" /span 

 threadPool = getDefaultThreadPool();

 requestMap = Collections.synchronizedMap( span new /span WeakHashMap Context, List RequestHandle ());

 clientHeaderMap = span new /span HashMap String, String 

 httpContext = span new /span SyncBasicHttpContext( span new /span BasicHttpContext());

 httpClient = span new /span DefaultHttpClient(cm, httpParams);

 httpClient.addRequestInterceptor( span new /span HttpRequestInterceptor() {

 span @Override /span 

 span public /span span void /span span process /span (HttpRequest request, HttpContext context) {

 span if /span (!request.containsHeader(HEADER_ACCEPT_ENCODING)) {

 request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);

 span for /span (String header : clientHeaderMap.keySet()) {

 span if /span (request.containsHeader(header)) {

 Header overwritten = request.getFirstHeader(header);

 Log.d(LOG_TAG,

 String.format( span "Headers were overwritten! (%s | %s) overwrites (%s | %s)" /span ,

 header, clientHeaderMap.get(header),

 overwritten.getName(), overwritten.getValue())

 span //remove the overwritten header /span 

 request.removeHeader(overwritten);

 request.addHeader(header, clientHeaderMap.get(header));

 httpClient.addResponseInterceptor( span new /span HttpResponseInterceptor() {

 span @Override /span 

 span public /span span void /span span process /span (HttpResponse response, HttpContext context) {

 span final /span HttpEntity entity = response.getEntity();

 span if /span (entity == span null /span ) {

 span return /span 

 span final /span Header encoding = entity.getContentEncoding();

 span if /span (encoding != span null /span ) {

 span for /span (HeaderElement element : encoding.getElements()) {

 span if /span (element.getName().equalsIgnoreCase(ENCODING_GZIP)) {

 response.setEntity( span new /span InflatingEntity(entity));

 span break /span 

 httpClient.addRequestInterceptor( span new /span HttpRequestInterceptor() {

 span @Override /span 

 span public /span span void /span span process /span ( span final /span HttpRequest request, span final /span HttpContext context) span throws /span 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);

 span if /span (authState.getAuthScheme() == span null /span ) {

 AuthScope authScope = span new /span AuthScope(targetHost.getHostName(), targetHost.getPort());

 Credentials creds = credsProvider.getCredentials(authScope);

 span if /span (creds != span null /span ) {

 authState.setAuthScheme( span new /span BasicScheme());

 authState.setCredentials(creds);

 }, span 0 /span 

 httpClient.setHttpRequestRetryHandler( span new /span RetryHandler(DEFAULT_MAX_RETRIES, DEFAULT_RETRY_SLEEP_TIME_MILLIS));

} /code ul li 1 /li li 2 /li li 3 /li li 4 /li li 5 /li li 6 /li li 7 /li li 8 /li li 9 /li li 10 /li li 11 /li li 12 /li li 13 /li li 14 /li li 15 /li li 16 /li li 17 /li li 18 /li li 19 /li li 20 /li li 21 /li li 22 /li li 23 /li li 24 /li li 25 /li li 26 /li li 27 /li li 28 /li li 29 /li li 30 /li li 31 /li li 32 /li li 33 /li li 34 /li li 35 /li li 36 /li li 37 /li li 38 /li li 39 /li li 40 /li li 41 /li li 42 /li li 43 /li li 44 /li li 45 /li li 46 /li li 47 /li li 48 /li li 49 /li li 50 /li li 51 /li li 52 /li li 53 /li li 54 /li li 55 /li li 56 /li li 57 /li li 58 /li li 59 /li li 60 /li li 61 /li li 62 /li li 63 /li li 64 /li li 65 /li li 66 /li li 67 /li li 68 /li li 69 /li li 70 /li li 71 /li li 72 /li li 73 /li li 74 /li li 75 /li li 76 /li li 77 /li li 78 /li li 79 /li li 80 /li li 81 /li li 82 /li li 83 /li li 84 /li li 85 /li li 86 /li li 87 /li li 88 /li li 89 /li li 90 /li li 91 /li li 92 /li /ul 
从代码的最顶层分析,构造参数传入的是SchemeRegistry对象,查看源码这是一个静态的方法,主要存储一些协议的东西

 public SchemeRegistry() {
        super();
        registeredSchemes = new ConcurrentHashMap String,Scheme
    }

上面的代码我们主要关注下addResponseInterceptor和addResponseInterceptor,此两个方法主要将我们的请求头和请求的实体加到HttpRequest队列中,对android1.5之前的熟悉的朋友都知道,在最早之前没有流行这些第三方之前我们就是通过HttpRequest来请求的,这等同于j2ee的HttpServletRequest.

接下来我们调运的就是AsyncHttpClient里面的各种get、post、delete等方法,通过看代码可以发现它们最终调用的都是sendRequest方法,如下:

 code style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: Source Code Pro, monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;" span /**

 * Puts a new request in queue as a new thread in pool to be executed

 * span @param /span client HttpClient to be used for request, can differ in single requests

 * span @param /span contentType MIME body type, for POST and PUT requests, may be null

 * span @param /span context Context of Android application, to hold the reference of request

 * span @param /span httpContext HttpContext in which the request will be executed

 * span @param /span responseHandler ResponseHandler or its subclass to put the response into

 * span @param /span uriRequest instance of HttpUriRequest, which means it must be of HttpDelete,

 * HttpPost, HttpGet, HttpPut, etc.

 * span @return /span RequestHandle of future request process

 */ /span 

 span protected /span RequestHandle span sendRequest /span (DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, ResponseHandlerInterface responseHandler, Context context) {

 span if /span (uriRequest == span null /span ) {

 span throw /span span new /span IllegalArgumentException( span "HttpUriRequest must not be null" /span 

 span if /span (responseHandler == span null /span ) {

 span throw /span span new /span IllegalArgumentException( span "ResponseHandler must not be null" /span 

 span if /span (responseHandler.getUseSynchronousMode() !responseHandler.getUsePoolThread()) {

 span throw /span span new /span IllegalArgumentException( span "Synchronous ResponseHandler used in AsyncHttpClient. You should create your response handler in a looper thread or use SyncHttpClient instead." /span 

 span if /span (contentType != span null /span ) {

 span if /span (uriRequest span instanceof /span HttpEntityEnclosingRequestBase ((HttpEntityEnclosingRequestBase) uriRequest).getEntity() != span null /span ) {

 Log.w(LOG_TAG, span "Passed contentType will be ignored because HttpEntity sets content type" /span 

 } span else /span {

 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 = span new /span RequestHandle(request);

 span if /span (context != span null /span ) {

 span // Add request to request map /span 

 List RequestHandle requestList = requestMap.get(context);

 span synchronized /span (requestMap) {

 span if /span (requestList == span null /span ) {

 requestList = Collections.synchronizedList( span new /span LinkedList RequestHandle 

 requestMap.put(context, requestList);

 requestList.add(requestHandle);

 Iterator RequestHandle iterator = requestList.iterator();

 span while /span (iterator.hasNext()) {

 span if /span (iterator.next().shouldBeGarbageCollected()) {

 iterator.remove();

 span return /span requestHandle;

 } /code ul li 1 /li li 2 /li li 3 /li li 4 /li li 5 /li li 6 /li li 7 /li li 8 /li li 9 /li li 10 /li li 11 /li li 12 /li li 13 /li li 14 /li li 15 /li li 16 /li li 17 /li li 18 /li li 19 /li li 20 /li li 21 /li li 22 /li li 23 /li li 24 /li li 25 /li li 26 /li li 27 /li li 28 /li li 29 /li li 30 /li li 31 /li li 32 /li li 33 /li li 34 /li li 35 /li li 36 /li li 37 /li li 38 /li li 39 /li li 40 /li li 41 /li li 42 /li li 43 /li li 44 /li li 45 /li li 46 /li li 47 /li li 48 /li li 49 /li li 50 /li li 51 /li li 52 /li li 53 /li li 54 /li li 55 /li li 56 /li li 57 /li li 58 /li li 59 /li li 60 /li li 61 /li li 62 /li /ul 
这个方法的主要作用是将一个新的请求添加到队列线程池中执行。 

调用本方法,主要实现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上传文件。








Android 彻底掌握 Handler 看这里就够了(下) 重点关注 Handler 的 post(Runnable) 与 sendMessage(Message msg) 有什么区别 Handler.post() Handler.getPostMessage() Handler.sendMessage() Handrle.dispatchMessage() Handrle.handleCallback() Looper.loop() 为什么不会阻塞主线程 MessageQueue.next() MessageQueue.nativePollOnce() android_os_MessageQueue_nativePollOnce
Android 彻底掌握 Handler 看这里就够了(上) Handler 允许你发送和处理与线程的 MessageQueue 关联的 Message 和 Runnable 对象。每个 Handler 实例都与一个线程和该线程的消息队列相关联。当你创建一个新的 Handler 时,它会绑定到一个 Looper。它会将消息和可运行对象传递到该 Looper 的消息队列,并在该 Looper 的线程上执行它们。