浅析Http框架 - Android-Async-http

现在主流的网络框架越来越多, Volley, okHttp, Android-Async-http. Android-Async-http是出现比较久的网络框架,用的人相当多. 后来Google结合HttpClient和HttpUrlConnection的优点又推出同样优秀的框架Volley.这些都是优秀的框架,值得我们去阅读源码学习. Android-Async-http我用过很长事件,但都没去看源码(鄙视下自己).直到最近有个朋友来问我这个框架内为何定义了HttpGet, 这个和系统的HttpGet有何区别? 我不能贸然回答他, 于是决定去看看源码了.


该框架的类源码很多, 浏览了大部分方法名和一些关键方法的实现. 主要是学习下大神的思路.下面通过几个关键类去了解:


AsyncHttpClient类

这应该是在使用过程中接触最多的类,当然还有各种回调的handler.所以应该猜到,这应该是集成度很高的类,里面有很多方法.看构造方法,AsyncHttpClient支持SSL,但是默认的构造方法是省略对SSL认证的支持.如果要添加SSL证书,只需要在构建AsyncHttpClient的方法中
  
  
[java] view plain copy
  1. new AsyncHttpClient(fixNoHttpResponseException, httpPort, httpsPort)  
将参数fixNoHttpResponseException设为true即可支持返回信任的安全套接字SSLSocketFactory.

扒一扒设置Cookie的方法:

[java]  view plain  copy
  1. /** 
  2.      * Sets an optional CookieStore to use when making requests 
  3.      * 
  4.      * @param cookieStore The CookieStore implementation to use, usually an instance of {@link 
  5.      *                    PersistentCookieStore} 
  6.      */  
  7.     public void setCookieStore(CookieStore cookieStore) {  
  8.         httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);  
  9.     }  

 
 
接着看构建AsyncHttpClient的所有构建方法,最终都会调用该方法(代码没贴全,有兴趣可以去看源码):
 
 
[java] view plain copy
  1. /** 
  2.      * Creates a new AsyncHttpClient. 
  3.      * 
  4.      * @param schemeRegistry SchemeRegistry to be used 
  5.      */  
  6.     public AsyncHttpClient(SchemeRegistry schemeRegistry) {  
  7.   
  8.         BasicHttpParams httpParams = new BasicHttpParams();  
  9.   
  10.         ConnManagerParams.setTimeout(httpParams, connectTimeout);  
  11.         ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(maxConnections));  
  12.         ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);  
  13.   
  14.         HttpConnectionParams.setSoTimeout(httpParams, responseTimeout);  
  15.         HttpConnectionParams.setConnectionTimeout(httpParams, connectTimeout);  
  16.         HttpConnectionParams.setTcpNoDelay(httpParams, true);  
  17.         HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE);  
  18.   
  19.         HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);  
  20.         //...  
  21.     }   

在这个方法中, 所有参数一目了然, 请求超时时间, 连接超时时间,最大连接数,header的添加等等参数都在这里得到设置处理,但很快就会发现一个重要的对象,threadPool. 这是获取的默认的线程池,为什么重要?快速浏览该类,发现一些蛛丝马迹:
 
 
[java] view plain copy
  1. AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context);  
  2.         threadPool.submit(request);  

看到上面的代码, 不禁要联想翩翩.没错,这的确是提交HTTP请求的实现.其实看到这里,我们大概猜到,框架中使用线程池去管理发送网络请求的所有线程.responseHandler是实现了封装接口,并且有回调方法的对象,比如我们在源码中所看到的BinaryHttpResponseHandler,DataAsyncHttpResponseHandler,JsonHttpResponseHandler等各种负责精细处理的handler都继承于AsyncHttpResponseHandler这个抽象类.抽象类我们都知道主要是规范子类,比如定义一些接口方法什么的.我们常用的onSuccess(...),onFailure(Throwable e),onFinish(),onRetry()等方法都在这里被定义,这些方法也理应不被实现,因为只是充当被回调的角色,等待HTTP请求后才被回调,而且回调想要处理的结果也不一样,有的是json,有的是binary,有的是String... 它们也应当在子类中被各自实现,得到不同的作用. 再来看,AsyncHttpResponseHandler的确实现ResponseHandlerInterface接口,也就是上面代码中所传进来的responseHandler.这里我们就明白,为何get,post等方法,我们要传各种handler(AsyncHttpResponseHandler的子类)进来.

这个类的亮点是蛮多的,等待大家发现.这里紧跟上面说到线程池,必须提及一个优秀的设计,在封装的sendRequest()方法中,作者使用了Map<Context, List<RequestHandle>> requestMap去缓存请求数,并不是来多少请求就抛多少进去线程池,这样肯定效率极低.而是将这些请求队列放入Map中,这样如果要取消某些请求,管理起来就非常方便.

相关代码比较分散,下面是缓存请求的部分代码:
  
  
[java] view plain copy
  1. responseHandler.setRequestHeaders(uriRequest.getAllHeaders());  
  2.         responseHandler.setRequestURI(uriRequest.getURI());  
  3.   
  4.         AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context);  
  5.         threadPool.submit(request);  
  6.         RequestHandle requestHandle = new RequestHandle(request);  
  7.   
  8.         if (context != null) {  
  9.             List<RequestHandle> requestList;  
  10.             // Add request to request map  
  11.             synchronized (requestMap) {  
  12.                 requestList = requestMap.get(context);  
  13.                 if (requestList == null) {  
  14.                     requestList = Collections.synchronizedList(new LinkedList<RequestHandle>());  
  15.                     requestMap.put(context, requestList);  
  16.                 }  
  17.             }  
  18.   
  19.             requestList.add(requestHandle);  
  20.   
  21.             Iterator<RequestHandle> iterator = requestList.iterator();  
  22.             while (iterator.hasNext()) {  
  23.                 if (iterator.next().shouldBeGarbageCollected()) {  
  24.                     iterator.remove();  
  25.                 }  
  26.             }  
  27.         }  
取消请求的代码直接看该类的cancelRequests(...),cancelAllRequests(...)相关方法就好.

AsyncHttpRequest类
上面的代码中还有一个AsyncHttpRequest类,它是被提交到线程中,所以应该是一个实现Runnable接口的类.其中newAsyncHttpRequest(...)这个方法的参数中,可见框架实现网络请求的方式的确是使用了系统的DefaultHttpClient.
  
  
[java] view plain copy
  1. protected AsyncHttpRequest newAsyncHttpRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, ResponseHandlerInterface responseHandler, Context context) {  
  2.         return new AsyncHttpRequest(client, httpContext, uriRequest, responseHandler);  
  3.     }  
既然是实现Runnable接口,重点应该放在run方法中:
  
  
[java] view plain copy
  1. @Override  
  2.     public void run() {  
  3.         if (isCancelled()) {  
  4.             return;  
  5.         }  
  6.   
  7.         // Carry out pre-processing for this request only once.  
  8.         if (!isRequestPreProcessed) {  
  9.             isRequestPreProcessed = true;  
  10.             onPreProcessRequest(this);  
  11.         }  
  12.   
  13.         if (isCancelled()) {  
  14.             return;  
  15.         }  
  16.   
  17.         responseHandler.sendStartMessage();  
  18.   
  19.         if (isCancelled()) {  
  20.             return;  
  21.         }  
  22.   
  23.         try {  
  24.             makeRequestWithRetries();  
  25.         } catch (IOException e) {  
  26.             if (!isCancelled()) {  
  27.                 responseHandler.sendFailureMessage(0nullnull, e);  
  28.             } else {  
  29.                 Log.e("AsyncHttpRequest""makeRequestWithRetries returned error", e);  
  30.             }  
  31.         }  
  32.   
  33.         if (isCancelled()) {  
  34.             return;  
  35.         }  
  36.   
  37.         responseHandler.sendFinishMessage();  
  38.   
  39.         if (isCancelled()) {  
  40.             return;  
  41.         }  
  42.   
  43.         // Carry out post-processing for this request.  
  44.         onPostProcessRequest(this);  
  45.   
  46.         isFinished = true;  
  47.     }  
思路大概是,首先检查这个request是否被取消,如果被取消则不发送请求直接返回,否则就用responseHandler去发请求了.由于ResponseHandlerInterface接口的方法在各个handler中已经实现,所以这里直接调用即可.代码看起来相当简洁!同时也看到run方法中好几个地方都去isCanCelled()检查请求是否取消.能比较有效管理请求.并不是说,只在开始run的时候检查一次是否取消后面就不再检查.因为用户可是随时都有可能取消操作的.
同时通过接收异常,方法中还有针对异常处理,和重新发请求的机制.代码简洁有力,逻辑清晰,再次赞叹大神的能力.

由于大家经常用该框架的接口方法,其实到了这里,我们对Android-Async-http框架已有初步的印象.知道比如访问超时,连接超时等这些参数在哪里被设置,网络请求如何被发送和被取消,取消和重发的机制又是怎样的等等. 下面我们看看Cookie如何被保存.
 
 
 
 
 

PersistentCookieStore类

框架中已经针对Cookie做了处理, 封装成PersistentCookieStore对象, 会保存在SharePreference中.进入的构建方法,会发现是这么实现的:

[java]  view plain  copy
  1. /** 
  2.      * Construct a persistent cookie store. 
  3.      * 
  4.      * @param context Context to attach cookie store to 
  5.      */  
  6.     public PersistentCookieStore(Context context) {  
  7.         cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0);  
  8.         cookies = new ConcurrentHashMap<String, Cookie>();  
  9.   
  10.         // Load any previously stored cookies into the store  
  11.         String storedCookieNames = cookiePrefs.getString(COOKIE_NAME_STORE, null);  
  12.         if (storedCookieNames != null) {  
  13.             String[] cookieNames = TextUtils.split(storedCookieNames, ",");  
  14.             for (String name : cookieNames) {  
  15.                 String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null);  
  16.                 if (encodedCookie != null) {  
  17.                     Cookie decodedCookie = decodeCookie(encodedCookie);  
  18.                     if (decodedCookie != null) {  
  19.                         cookies.put(name, decodedCookie);  
  20.                     }  
  21.                 }  
  22.             }  
  23.   
  24.             // Clear out expired cookies  
  25.             clearExpired(new Date());  
  26.         }  
  27.     }  

cookiePrefs就是SharePreference对象.代码中的cookies是存放cookie的Map对象.PersistentCookieStore类已经便捷的提供了clear() , deleteCookie(Cookie cookie), List<Cookie> getCookies(), addCookie(Cookie cookie)等方法.直接new PersistentCookieStore(Context context) 就能获取存储的Cookie, 并自动清除过期的cookies, 然后set入AsyncHttpClient中. 当然在应用的使用过程中, 无论是AsyncHttpClient还是系统自带HttpClient., 它们就像电脑上面的浏览器, 只要保持一直用同一个对象去发送诸如GET, POST的这些请求, 对象是会自动保持cookie的, 所以适用过程中并不需要担心cookie的问题. 本地化存储的好处, 是在下次打开应用时还能使用之前的操作记录.

借鉴这种思路, 我们在使用系统的DefaultHttpClient时,也能对其子类使用相同的处理方法去本地化保存Cookie了.


BinaryHttpResponseHandler类

然后来看其中一个Handler类.依然是抽象类, onSuccess(...), onFailure(...)等这些方法依然是抽象方法. 知道多态继承和抽象的童鞋, 应该都知道为啥这么干了, 因为这些方法基本是在回调的时候才去实现这些接口方法的. 为了降藕,提高功能模块的灵活性和可扩展, 对外只提供接口, 不提供实现, 这是优秀的架构设计.


通过简单的BinaryHttpResponseHandler类来了解其他Handler类的设计思路,Handler类必须结合AsyncHttpRequest和AsyncHttpResponseHandler这2个类去理解.在AsyncHttpRequest的run方法中,sendStartMessage()发出请求, 本质还是通过HttpClient的excute()方法去实现. 得到的返回结果又使用sendResponseMessage(response)去解析.这些方法要去AsyncHttpResponseHandler和它的子类BinaryHttpResponseHandler去看.如果应用中是通过BinaryHttpResponseHandler发请求,那么sendResponseMessage(response)方法会首先回调BinaryHttpResponseHandler中的sendResponseMessage(response)去解析, 当然有些子类比如JsonHttpResPonseHandler是没有sendResponseMessage(...)方法的, 那么就直接交给AsyncHttpResponseHandler的该方法去处理. 就像BinaryHttpResponseHandler类, 在sendResponseMessage(...)中处理完结果还是会super.sendResponseMessage(...)调用父类的方法去继续处理, 因为onSuccess(...), onFailure(...)等的这些方法的回调机制都在父类AsyncHttpResponseHandler中实现.  这里我们再次看到这种设计的思路, 子类尽可能的去实现去解析,做一些具体的处理, 而将一些相同的可封装的方法都封装在父类中.


回到AsyncHttpResponseHandler的sendResponseMessage(...)方法:

[java]  view plain  copy
  1. Override  
  2.     public void sendResponseMessage(HttpResponse response) throws IOException {  
  3.         // do not process if request has been cancelled  
  4.         if (!Thread.currentThread().isInterrupted()) {  
  5.             StatusLine status = response.getStatusLine();  
  6.             byte[] responseBody;  
  7.             responseBody = getResponseData(response.getEntity());  
  8.             // additional cancellation check as getResponseData() can take non-zero time to process  
  9.             if (!Thread.currentThread().isInterrupted()) {  
  10.                 if (status.getStatusCode() >= 300) {  
  11.                     sendFailureMessage(status.getStatusCode(), response.getAllHeaders(), responseBody, new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()));  
  12.                 } else {  
  13.                     sendSuccessMessage(status.getStatusCode(), response.getAllHeaders(), responseBody);  
  14.                 }  
  15.             }  
  16.         }  
  17.     }  

通过查看sendFailureMessage(...)和sendSuccessMessage(...)的方法代码, 看到里面利用Handler对象去进行通信.一直追踪, 终于发现这段代码:

[java]  view plain  copy
  1. protected void handleMessage(Message message) {  
  2.         Object[] response;  
  3.   
  4.         try {  
  5.             switch (message.what) {  
  6.                 case SUCCESS_MESSAGE:  
  7.                     response = (Object[]) message.obj;  
  8.                     if (response != null && response.length >= 3) {  
  9.                         onSuccess((Integer) response[0], (Header[]) response[1], (byte[]) response[2]);  
  10.                     } else {  
  11.                         Log.e(LOG_TAG, "SUCCESS_MESSAGE didn't got enough params");  
  12.                     }  
  13.                     break;  
  14.                 case FAILURE_MESSAGE:  
  15.                     response = (Object[]) message.obj;  
  16.                     if (response != null && response.length >= 4) {  
  17.                         onFailure((Integer) response[0], (Header[]) response[1], (byte[]) response[2], (Throwable) response[3]);  
  18.                     } else {  
  19.                         Log.e(LOG_TAG, "FAILURE_MESSAGE didn't got enough params");  
  20.                     }  
  21.                     break;  
  22.                 case START_MESSAGE:  
  23.                     onStart();  
  24.                     break;  
  25.                 case FINISH_MESSAGE:  
  26.                     onFinish();  
  27.                     break;  
  28.                 case PROGRESS_MESSAGE:  
  29.                     response = (Object[]) message.obj;  
  30.                     if (response != null && response.length >= 2) {  
  31.                         try {  
  32.                             onProgress((Long) response[0], (Long) response[1]);  
  33.                         } catch (Throwable t) {  
  34.                             Log.e(LOG_TAG, "custom onProgress contains an error", t);  
  35.                         }  
  36.                     } else {  
  37.                         Log.e(LOG_TAG, "PROGRESS_MESSAGE didn't got enough params");  
  38.                     }  
  39.                     break;  
  40.                 case RETRY_MESSAGE:  
  41.                     response = (Object[]) message.obj;  
  42.                     if (response != null && response.length == 1) {  
  43.                         onRetry((Integer) response[0]);  
  44.                     } else {  
  45.                         Log.e(LOG_TAG, "RETRY_MESSAGE didn't get enough params");  
  46.                     }  
  47.                     break;  
  48.                 case CANCEL_MESSAGE:  
  49.                     onCancel();  
  50.                     break;  
  51.             }  
  52.         } catch(Throwable error) {  
  53.             onUserException(error);  
  54.         }  
  55.     }  

到了这里, 我们对一个AsyncHttpResponseHandler的子类所必须实现的onSuccess(...), onFailure(...), onFinish(...)等这些方法是如何被回调的, 以及框架中从请求发起到取消, 或到返回的结果如何解析, 如何判断和处理异常, 有比较清晰的认识. 而其他的AsyncHttpResponseHandler子类都跟BinaryHttpResponseHandler类似.原理是一样的. 


对待一个框架, 一开始不建议逐个类盲目去看, 特别当框架中类也多,代码也多, 简直无从入手. 如果还逐行代码去看必然花费大量时间.优秀的框架, 优秀的方法代码, 必然在设计上是思路清晰的, 并且有关键的注释帮助理解. 这样不但方便以后自己持续的维护项目代码, 也帮助后来进入的开发者能快速的理解代码进入项目的设计中. 另一方面, 我们以后去设计功能模块, 敲代码, 关键的地方也请写上必要的注释, 在设计尽量上将功能模块之间处理的合理, 比如提高可复用, 降藕等等.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值