AsyncHttpClient应用了Android的Handler发送消息机制。你也可以把AsyncHttpClient应用在Service中或者后台线程中,库代码会自动识别出它所运行的context。它的feature包括:
1. 发送异步http请求,在匿名callback对象中处理response;
2. http请求发生在UI线程之外;
3. 内部采用线程池来处理并发请求;
4. GET/POST 参数构造,通过RequestParams类。
5. 内置多部分文件上传,不需要第三方库支持;
6. 流式Json上传,不需要额外的库;
7. 能处理环行和相对重定向;
8. 和你的app大小相比来说,库的size很小,所有的一切只有90kb;
9. 自动智能的请求重试机制在各种各样的移动连接环境中;
10. 自动的gzip响应解码;
11. 内置多种形式的响应解析,有原生的字节流,string,json对象,甚至可以将response写到文件中;
12. 永久的cookie保存,内部实现用的是Android的SharedPreferences;
13. 通过BaseJsonHttpResponseHandler和各种json库集成;
14. 支持SAX解析器;
15. 支持各种语言和content编码,不仅仅是UTF-8。
android-async-http来写代码是怎么实现,简单来说你只需要3步:
1. 创建一个AsyncHttpClient;
2. (可选的)通过RequestParams对象设置请求参数;
3. 调用AsyncHttpClient的某个get方法,传递你需要的(成功和失败时)callback接口实现,一般都是匿名内部类,实现了AsyncHttpResponseHandler,类库自己也提供了好些现成的response handler,你一般不需要自己创建一个。
通过AsyncHttpClient类的实例就可以执行网络请求,包括get、put、post、head、delete。并指定一个ResponseHandlerInterface的实例接收请求结果。
public class RequestManager {
private static AsyncHttpClient client = new AsyncHttpClient();
static {
client.setTimeout(30000);// 设置链接超时,如果不设置,默认为10s
}
public static AsyncHttpClient getClient() {
return client;
}
/**
* http Get 请求
*
* @param requestCode 请求码
* @param url 请求url 地址
* @param params 请求参数集合
* @param callback 回调函数
*/
public static void get(final int requestCode, String url, RequestParams params, final RequestCallback callback) {
if (params == null) params = new RequestParams();
LogUtils.i("http-get", url + "?" + params.toString());
client.get(url, params, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
callback.onFailureCallback(requestCode, responseString);
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseString) {
callback.onSuccessCallback(requestCode, responseString);
}
});
}
/**
* http Post 请求
*
* @param requestCode 请求码
* @param url 请求url 地址
* @param params 请求参数集合
* @param callback 回调函数
*/
public static void post(final int requestCode, String url, RequestParams params, final RequestCallback callback) {
if (params == null) params = new RequestParams();
LogUtils.i("http-post", url + "?" + params.toString());
client.post(url, params, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString,
Throwable throwable) {
callback.onFailureCallback(requestCode, responseString);
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseString) {
callback.onSuccessCallback(requestCode, responseString);
}
});
}
/**
* http Post 请求 ,指定CONTENT_TYPE 为application/json
*
* @param context context
* @param requestCode 请求码
* @param url 请求url 地址
* @param params 请求参数集合
* @param callback 回调函数
*/
public static void post(Context context, final int requestCode, String url, String params,
final RequestCallback callback) {
LogUtils.i("http-post", url + "?" + params);
ByteArrayEntity entity = null;
try {
entity = new ByteArrayEntity(params.getBytes("UTF-8"));
entity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
client.post(context, url, entity, "application/json", new JsonHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
callback.onSuccessCallback(requestCode, response != null ? response.toString() : "");
}
@Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
callback.onFailureCallback(requestCode, errorResponse != null ? errorResponse.toString() : "");
}
});
}
/**
* http Delete 请求
*
* @param requestCode 请求码
* @param url 请求url 地址
* @param params 请求参数集合
* @param callback 回调函数
*/
public static void delete(final int requestCode, String url, RequestParams params, final RequestCallback callback) {
if (params == null) params = new RequestParams();
LogUtils.i("http-delete", url + "?" + params.toString());
client.delete(url, params, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
callback.onFailureCallback(requestCode, responseString);
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseString) {
callback.onSuccessCallback(requestCode, responseString);
}
});
}
/**
* http Put 请求
*
* @param requestCode 请求码
* @param url 请求url 地址
* @param params 请求参数集合
* @param callback 回调函数
*/
public static void put(final int requestCode, String url, RequestParams params, final RequestCallback callback) {
if (params == null) params = new RequestParams();
LogUtils.i("http-put", url + "?" + params.toString());
client.put(url, params, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
callback.onFailureCallback(requestCode, responseString);
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseString) {
callback.onSuccessCallback(requestCode, responseString);
}
});
}
/**
* http Put 请求 指定CONTENT_TYPE 为application/json
*
* @param context context
* @param requestCode 请求码
* @param url 请求url 地址
* @param params 请求参数集合
* @param callback 回调函数
*/
public static void put(Context context, final int requestCode, String url, String params, final RequestCallback callback) {
LogUtils.e("http-request", url + "?" + params);
ByteArrayEntity entity = null;
try {
entity = new ByteArrayEntity(params.getBytes("UTF-8"));
entity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
client.put(context, url, entity, "application/json", new JsonHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
callback.onSuccessCallback(requestCode, response != null ? response.toString() : "");
}
@Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
callback.onFailureCallback(requestCode, errorResponse != null ? errorResponse.toString() : "");
}
});
}
}
AsyncHttpRequest
继承自Runnabler,被submit至线程池执行网络请求并发送start,success等消息
AsyncHttpResponseHandler
接收请求结果,一般重写onSuccess及onFailure接收请求成功或失败的消息,还有onStart,onFinish等消息
TextHttpResponseHandler
继承自AsyncHttpResponseHandler,只是重写了AsyncHttpResponseHandler的onSuccess和onFailure方法,将请求结果由byte数组转换为String
JsonHttpResponseHandler
继承自TextHttpResponseHandler,同样是重写onSuccess和onFailure方法,将请求结果由String转换为JSONObject或JSONArray
BaseJsonHttpResponseHandler
继承自TextHttpResponseHandler,是一个泛型类,提供了parseResponse方法,子类需要提供实现,将请求结果解析成需要的类型,子类可以灵活地使用解析方法,可以直接原始解析,使用gson等。
RequestParams
请求参数,可以添加普通的字符串参数,并可添加File,InputStream上传文件
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方法。
1.调用AsyncHttpClient的get或post等方法发起网络请求
2.所有的请求都走了sendRequest,在sendRequest中把请求封装为了AsyncHttpRequest,并添加到线程池执行
3.当请求被执行时(即AsyncHttpRequest的run方法),执行AsyncHttpRequest的makeRequestWithRetries方法执行实际的请求,当请求失败时可以重试。并在请求开始,结束,成功或失败时向请求时传的ResponseHandlerInterface实例发送消息
4.基本上使用的都是AsyncHttpResponseHandler的子类,调用其onStart,onSuccess等方法返回请求结果
Android-Async-Http的使用非常简单,通过AsyncHttpClient发起请求就可以了,如果需要添加参数,直接传一个RequestParams过去,而且参数可以是String、File和InputStream,可以很方便地上传文件。
每个请求都需要传一个ResponseHandlerInterface的实例用以接收请求结果或请求失败,请求结束等通知,一般是AsyncHttpResponseHandler的子类。
通过BinaryHttpResponseHandler可以发起二进制请求,如请求图片。
通过TextHttpResponseHandler可以发起返回结果为字符串的请求,一般这个使用较多。
也可以使用它的子类JsonHttpResponseHandler,返回结果是一个JSONObject或JSONArray。不过感觉这个类作用不大,一是有另一个类BaseJsonHttpResponseHandler,可以直接解析返回的JSON数据,二是JsonHttpResponseHandler的方法太复杂了,有太多的onSuccess和onFailure方法,都不知道重写哪个了。
这个类库还有一点不足,就是onSuccess等方法一般会在主线程执行。
public AsyncHttpResponseHandler() {
boolean missingLooper = null == Looper.myLooper();
// Try to create handler
if (!missingLooper)
handler = new ResponderHandler(this);
else {
// There is no Looper on this thread so synchronous mode should be used.
handler = null;
setUseSynchronousMode(true);
Log.i(LOG_TAG, "Current thread has not called Looper.prepare(). Forcing synchronous mode.");
}
// Init Looper by calling postRunnable without an argument.
postRunnable(null);
}
可以看到,内部使用了Handler,当新建AsyncHttpResponseHandler的实例的时候会获取当前线程的Looper,如果为空就启用同步模式,即所有的回调都会在执行请求的线程中执行,当在一个普通的后台线程时这样执行是正常的,而我们一般都会在主线程发请请求,结果就是所有的回调都会在主线程中执行,这就限制了我们在onSuccess中执行耗时操作,比如请求成功后将数据持久化到数据库。
不过可以看到创建Handler的时候使用了Looper对象,所以我们就可以改进一下其构造函数,添加一个Looper参数(同步修改子类),这样所有的回调就都会在Looper所在线程执行,这样我们只需要开启一个HandlerThread就行了。但这样和Looper为空时一样有一个弊端,
1)如果要更新UI操作的话,还需要向一个主线程的Handler发送消息让UI更新。
2)还有第二个弊端,所有回调都在同一个HandlerThread中执行,如果一个处理耗时太久会阻塞后面的请求结果处理,如果只是简单地写个数据库影响应该不大,如果真耗时太久,为这个耗时处理再开个线程吧。