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

asynchttpclient源码分析

2015-10-11 00:35 573 查看
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或者是字节流了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: