asynchttpclient源码分析

来源:互联网 发布:淘宝客推广培训 编辑:程序博客网 时间:2024/06/06 17:10

1. 介绍
使用Android自带httpclient编写网络请求是一件非常痛苦的事情,你需要熟知http请求首部字段、实体首部等的含义,还需要开启子线程执行相关操作然后将执行结果返回。首部字段玲琅满目和请求结果格式的不统一(json,string,字节流)是编写网络请求代码的痛点,市面上有很多的开源框架帮助我们完成了这些繁杂和重复的操作,比较常用的有:xUtil,aFinal,okHttp,volley,retrofit,android-async-http等。
各个框架原理大致相似,此篇分析android-async-http源码。个人对开源框架的态度是没有必要深抠实现细节,但是大致流程要知道,以免遇到问题不知所措。还有开源框架的模式也是值得我们去学习和模仿的。
android-async-http的项目地址在: http://loopj.com/android-async-http/

2. 源码分析
这是官方提供的使用实例

AsyncHttpClient client = new AsyncHttpClient();client.get("https://www.google.com", new AsyncHttpResponseHandler() {    @Override    public void onStart() {        // called before request is started    }    @Override    public void onSuccess(int statusCode, Header[] headers, byte[] response) {        // called when response HTTP status is "200 OK"    }    @Override    public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {        // called when response HTTP status is "4XX" (eg. 401, 403, 404)    }    @Override    public void onRetry(int retryNo) {        // called when request is retried    }});
  • 请求预处理

这里的url为baseUrl,内部会把通过getUrlWithQueryString方法将url和RequestParams拼接为全连接形式的字符串,然后将该字符串作为参数创建为内部的一个HttpGet对象,并调用sendReques方法将请求组织成内部使用的一个AsyncHttpRequest对象
这里写图片描述

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();                }            }        }

第1行:将请求组成为一个AsyncHttpRequest对象,该对象为一个Runnable对象,负责网络请求的连接,请求结果的分发、逻辑取消、重试等逻辑
第2行:将AsyncHttpRequest投递到内部的一个线程池中,自然AsyncHttpRequest内部逻辑在该线程获得cpu资源的时候执行
第3行:将AsyncHttpRequest作为参数创建为一个RequestHandle实例,该类负责请求的取消功能
第5-23行:AsyncHttpClient 内部维持了一个Map,以context为key,RequestHandle集合为值,这样就可以通过context取消该context绑定的请求和处理线程关系了。

  • 实际网络请求、重试逻辑
    这里写图片描述
    AsyncHttpRequest内部有很多的内部属性,前几个是网络请求相关api,isCancelled标示该请求是否被取消,executionCount用来记录请求执行次数从而处理重试逻辑,cancelIsNotified用来标示是否已经处理过cancel消息,isFinished标示请求是否完成(这里的完成跟请求结果成功、失败、被取消无关),isRequestPreProcessed标示在请求前的一个回调方法(该方法在子线程中执行)。
@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 {                AsyncHttpClient.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;    }

第7-10行:处理onPreProcessRequest函数,该函数在实际网络请求前执行且只会被执行一次,目前该方法默认空置,可由子类扩展
第17行:发出开始消息,代表开始网络请求
第23-30行:发出网络请求,请求失败会发出失败消息
第37行:发出网络请求完成消息,结果可能成功也可能失败
第44行:处理onPostProcessRequest函数,与onPreProcessRequest对应,默认空置,可由子类拓展

makeRequestWithRetries函数主要是配合HttpRequestRetryHandler接口完成重试操作,实际网络请求在makeRequest中执行

 private void makeRequest() throws IOException {        if (isCancelled()) {            return;        }        // Fixes #115        if (request.getURI().getScheme() == null) {            // subclass of IOException so processed in the caller            throw new MalformedURLException("No valid URI scheme was provided");        }        if (responseHandler instanceof RangeFileAsyncHttpResponseHandler) {            ((RangeFileAsyncHttpResponseHandler) responseHandler).updateRequestHeaders(request);        }        HttpResponse response = client.execute(request, context);        if (isCancelled()) {            return;        }        // Carry out pre-processing for this response.        responseHandler.onPreProcessResponse(responseHandler, response);        if (isCancelled()) {            return;        }        // The response is ready, handle it.        responseHandler.sendResponseMessage(response);        if (isCancelled()) {            return;        }        // Carry out post-processing for this response.        responseHandler.onPostProcessResponse(responseHandler, response);    }

这样就把执行结果以及各种状态消息统统传递给了ResponseHandlerInterface,下面再来看消息的分发

  • 执行结果以及状态消息的分发
    执行结果和消息的分发操作在AsyncHttpResponseHandler类中实现的
    这里写图片描述
    是根据useSynchronousMode这个属性来判断分发操作在那个线程执行,分发操作比较简单,比较重要的是线程的选择,是在setUseSynchronousMode这一个方法中完成的。
    首先当我们创建一个AsyncHttpResponseHandler子类对象的时候,默认会通过this(null)执行该构造方法
 public AsyncHttpResponseHandler(Looper looper) {        this.looper = looper == null ? Looper.myLooper() : looper;        // Use asynchronous mode by default.        setUseSynchronousMode(false);        // Do not use the pool's thread to fire callbacks by default.        setUsePoolThread(false);    }

这里参数默认为空,所以会通过Looper.myLooper获取当前线程ThreadLocal存储的那个Looper然后赋值给this.looper属性,然后调用setUseSynchronousMode方法操作Handler

 public void setUseSynchronousMode(boolean sync) {        // A looper must be prepared before setting asynchronous mode.        if (!sync && looper == null) {            sync = true;            AsyncHttpClient.log.w(LOG_TAG, "Current thread has not called Looper.prepare(). Forcing synchronous mode.");        }        // If using asynchronous mode.        if (!sync && handler == null) {            // Create a handler on current thread to submit tasks            handler = new ResponderHandler(this, looper);        } else if (sync && handler != null) {            // TODO: Consider adding a flag to remove all queued messages.            handler = null;        }        useSynchronousMode = sync;    }

这里会根据是否同步和Looper的有无,来创建Handler或者置handler为null,后边sendMessage方法根据handler是否为null来执行同步回调还是异步回调,然后定义了好多种不同类型的回调类供我们选择是将结果处理为json、string或者是字节流了。

1 0
原创粉丝点击