您的位置:首页 > 理论基础 > 计算机网络

[Android]浅析Http框架 - Android-Async-http

2015-06-02 23:59 429 查看
现在主流的网络框架越来越多, Volley, okHttp, Android-Async-http. Android-Async-http是出现比较久的网络框架,用的人相当多. 后来Google结合HttpClient和HttpUrlConnection的优点又推出同样优秀的框架Volley.这些都是优秀的框架,值得我们去阅读源码学习. Android-Async-http我用过很长事件,但都没去看源码(鄙视下自己).直到最近有个朋友来问我这个框架内为何定义了HttpGet, 这个和系统的HttpGet有何区别? 我不能贸然回答他, 于是决定去看看源码了.该框架的类源码很多, 浏览了大部分方法名和一些关键方法的实现. 主要是学习下大神的思路.下面通过几个关键类去了解:
AsyncHttpClient类
这应该是在使用过程中接触最多的类,当然还有各种回调的handler.所以应该猜到,这应该是集成度很高的类,里面有很多方法.看构造方法,AsyncHttpClient支持SSL,但是默认的构造方法是省略对SSL认证的支持.如果要添加SSL证书,只需要在构建AsyncHttpClient的方法中
new AsyncHttpClient(fixNoHttpResponseException, httpPort, httpsPort)
[code]将参数fixNoHttpResponseException设为true即可支持返回信任的安全套接字SSLSocketFactory.
扒一扒设置Cookie的方法:
/**
     * Sets an optional CookieStore to use when making requests
     *
     * @param cookieStore The CookieStore implementation to use, usually an instance of {@link
     *                    PersistentCookieStore}
     */
    public void setCookieStore(CookieStore cookieStore) {
        httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
    }
接着看构建AsyncHttpClient的所有构建方法,最终都会调用该方法(代码没贴全,有兴趣可以去看源码):
/**     * 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);        //...    } 
在这个方法中, 所有参数一目了然, 请求超时时间, 连接超时时间,最大连接数,header的添加等等参数都在这里得到设置处理,但很快就会发现一个重要的对象,threadPool. 这是获取的默认的线程池,为什么重要?快速浏览该类,发现一些蛛丝马迹:
AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context);        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中,这样如果要取消某些请求,管理起来就非常方便.
相关代码比较分散,下面是缓存请求的部分代码:
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) {            List<RequestHandle> requestList;            // Add request to request map            synchronized (requestMap) {                requestList = requestMap.get(context);                if (requestList == null) {                    requestList = Collections.synchronizedList(new LinkedList<RequestHandle>());                    requestMap.put(context, requestList);                }            }            requestList.add(requestHandle);            Iterator<RequestHandle> iterator = requestList.iterator();            while (iterator.hasNext()) {                if (iterator.next().shouldBeGarbageCollected()) {                    iterator.remove();                }            }        }
取消请求的代码直接看该类的cancelRequests(...),cancelAllRequests(...)相关方法就好.
AsyncHttpRequest类
上面的代码中还有一个AsyncHttpRequest类,它是被提交到线程中,所以应该是一个实现Runnable接口的类.其中newAsyncHttpRequest(...)这个方法的参数中,可见框架实现网络请求的方式的确是使用了系统的DefaultHttpClient.
protected AsyncHttpRequest newAsyncHttpRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, ResponseHandlerInterface responseHandler, Context context) {        return new AsyncHttpRequest(client, httpContext, uriRequest, responseHandler);    }
[code]
既然是实现Runnable接口,重点应该放在run方法中:
@Override    public void run() {        if (isCancelled()) {            return;        }        // Carry out pre-processing for this request only once.        if (!isRequestPreProcessed) {            isRequestPreProcessed = true;            onPreProcessRequest(this);        }        if (isCancelled()) {            return;        }        responseHandler.sendStartMessage();        if (isCancelled()) {            return;        }        try {            makeRequestWithRetries();        } catch (IOException e) {            if (!isCancelled()) {                responseHandler.sendFailureMessage(0, null, null, e);            } else {                Log.e("AsyncHttpRequest", "makeRequestWithRetries returned error", e);            }        }        if (isCancelled()) {            return;        }        responseHandler.sendFinishMessage();        if (isCancelled()) {            return;        }        // Carry out post-processing for this request.        onPostProcessRequest(this);        isFinished = true;    }
思路大概是,首先检查这个request是否被取消,如果被取消则不发送请求直接返回,否则就用responseHandler去发请求了.由于ResponseHandlerInterface接口的方法在各个handler中已经实现,所以这里直接调用即可.代码看起来相当简洁!同时也看到run方法中好几个地方都去isCanCelled()检查请求是否取消.能比较有效管理请求.并不是说,只在开始run的时候检查一次是否取消后面就不再检查.因为用户可是随时都有可能取消操作的.
同时通过接收异常,方法中还有针对异常处理,和重新发请求的机制.代码简洁有力,逻辑清晰,再次赞叹大神的能力.
由于大家经常用该框架的接口方法,其实到了这里,我们对Android-Async-http框架已有初步的印象.知道比如访问超时,连接超时等这些参数在哪里被设置,网络请求如何被发送和被取消,取消和重发的机制又是怎样的等等. 下面我们看看Cookie如何被保存.
PersistentCookieStore类框架中已经针对Cookie做了处理, 封装成PersistentCookieStore对象, 会保存在SharePreference中.进入的构建方法,会发现是这么实现的:
/**     * Construct a persistent cookie store.     *     * @param context Context to attach cookie store to     */    public PersistentCookieStore(Context context) {        cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0);        cookies = new ConcurrentHashMap<String, Cookie>();        // Load any previously stored cookies into the store        String storedCookieNames = cookiePrefs.getString(COOKIE_NAME_STORE, null);        if (storedCookieNames != null) {            String[] cookieNames = TextUtils.split(storedCookieNames, ",");            for (String name : cookieNames) {                String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null);                if (encodedCookie != null) {                    Cookie decodedCookie = decodeCookie(encodedCookie);                    if (decodedCookie != null) {                        cookies.put(name, decodedCookie);                    }                }            }            // Clear out expired cookies            clearExpired(new Date());        }    }
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(...)方法:
Override    public void sendResponseMessage(HttpResponse response) throws IOException {        // do not process if request has been cancelled        if (!Thread.currentThread().isInterrupted()) {            StatusLine status = response.getStatusLine();            byte[] responseBody;            responseBody = getResponseData(response.getEntity());            // additional cancellation check as getResponseData() can take non-zero time to process            if (!Thread.currentThread().isInterrupted()) {                if (status.getStatusCode() >= 300) {                    sendFailureMessage(status.getStatusCode(), response.getAllHeaders(), responseBody, new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()));                } else {                    sendSuccessMessage(status.getStatusCode(), response.getAllHeaders(), responseBody);                }            }        }    }
通过查看sendFailureMessage(...)和sendSuccessMessage(...)的方法代码, 看到里面利用Handler对象去进行通信.一直追踪, 终于发现这段代码:
protected void handleMessage(Message message) {        Object[] response;        try {            switch (message.what) {                case SUCCESS_MESSAGE:                    response = (Object[]) message.obj;                    if (response != null && response.length >= 3) {                        onSuccess((Integer) response[0], (Header[]) response[1], (byte[]) response[2]);                    } else {                        Log.e(LOG_TAG, "SUCCESS_MESSAGE didn't got enough params");                    }                    break;                case FAILURE_MESSAGE:                    response = (Object[]) message.obj;                    if (response != null && response.length >= 4) {                        onFailure((Integer) response[0], (Header[]) response[1], (byte[]) response[2], (Throwable) response[3]);                    } else {                        Log.e(LOG_TAG, "FAILURE_MESSAGE didn't got enough params");                    }                    break;                case START_MESSAGE:                    onStart();                    break;                case FINISH_MESSAGE:                    onFinish();                    break;                case PROGRESS_MESSAGE:                    response = (Object[]) message.obj;                    if (response != null && response.length >= 2) {                        try {                            onProgress((Long) response[0], (Long) response[1]);                        } catch (Throwable t) {                            Log.e(LOG_TAG, "custom onProgress contains an error", t);                        }                    } else {                        Log.e(LOG_TAG, "PROGRESS_MESSAGE didn't got enough params");                    }                    break;                case RETRY_MESSAGE:                    response = (Object[]) message.obj;                    if (response != null && response.length == 1) {                        onRetry((Integer) response[0]);                    } else {                        Log.e(LOG_TAG, "RETRY_MESSAGE didn't get enough params");                    }                    break;                case CANCEL_MESSAGE:                    onCancel();                    break;            }        } catch(Throwable error) {            onUserException(error);        }    }
到了这里, 我们对一个AsyncHttpResponseHandler的子类所必须实现的onSuccess(...), onFailure(...), onFinish(...)等这些方法是如何被回调的, 以及框架中从请求发起到取消, 或到返回的结果如何解析, 如何判断和处理异常, 有比较清晰的认识. 而其他的AsyncHttpResponseHandler子类都跟BinaryHttpResponseHandler类似.原理是一样的. 对待一个框架, 一开始不建议逐个类盲目去看, 特别当框架中类也多,代码也多, 简直无从入手. 如果还逐行代码去看必然花费大量时间.优秀的框架, 优秀的方法代码, 必然在设计上是思路清晰的, 并且有关键的注释帮助理解. 这样不但方便以后自己持续的维护项目代码, 也帮助后来进入的开发者能快速的理解代码进入项目的设计中. 另一方面, 我们以后去设计功能模块, 敲代码, 关键的地方也请写上必要的注释, 在设计尽量上将功能模块之间处理的合理, 比如提高可复用, 降藕等等.对HTTP框架Android-Async-http的浅析就到此了, 因为是浅析, 重在理解主要的实现思路, 很多点并没有展开讲, 有兴趣的童鞋可以自行下载源码去看哦.Android-Async-http源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: