如下是官方文档描述此库的特点:
All requests are made outside of your app’s main UI thread, but any callback logic will be executed on the same thread as the callback was created using Android’s Handler message passing.
•Using upstream HttpClient of version 4.3.6 instead of Android provided DefaultHttpClient
•Compatible with Android API 23 and higher
•Make asynchronous HTTP requests, handle responses in anonymous callbacks
•HTTP requests happen outside the UI thread
•Requests use a threadpool to cap concurrent resource usage
•GET/POST params builder (RequestParams)
•Multipart file uploads with no additional third party libraries
•Streamed JSON uploads with no additional libraries
•Handling circular and relative redirects
•Tiny size overhead to your application, only 90kb for everything
•Automatic smart request retries optimized for spo?y mobile connections
•Automatic gzip response decoding support for super-fast requests
•Binary protocol communication with BinaryHttpResponseHandler
•Built-in response parsing into JSON with JsonHttpResponseHandler
•Saving response directly into file with FileAsyncHttpResponseHandler
•Persistent cookie store, saves cookies into your app’s SharedPreferences
•Integration with Jackson JSON, Gson or other JSON (de)serializing libraries with BaseJsonHttpResponseHandler
•Support for SAX parser with SaxAsyncHttpResponseHandler
•Support for languages and content encodings, not just UTF-8
•1、兼容Android API23或更高版本
•2、发送异步的http请求,在匿名的回调callback中处理响应response
•3、Http的请求发生在主线程之外
•4、使用线程池处理并发请求
•5、使用RequestParams构造GET、POST请求参数
•6、流式Json上传,无需三方库支持
•7、能处理环形和相对重定向
•8、内置multiPart file 上传,无需第三方库支持
•9、相比app来说库很小,仅仅只有90k
•10、针对移动连接自动智能的请求重试优化机制
•11、自动的gzip响应解码
•12、支持字节流响应处理 BinaryHttpResponseHandler
•13、内置Json文本响应处理 JsonHttpResponseHandler
•14、持久化Cookie信息,将Cookie信息保存在应用的SharedPreference中
•15、通过实现抽象类BaseJsonHttpResponseHandler可以无缝对接三方Json解析库
•16、支持SAX解析器 SaxAsyncHttpResponseHandler
•17、支持各种语言和content编码,不止是UTF-8
Android-Async-Http 源码版本1.4.9
在AsyncHttpClient的构造方法中有对连接各种参数的设置,并实例化了一个默认的线程池threadPool(Executors.newCachedThreadPool)用于提交请求任务AsyncHttpRequest,接着初始化了httpClient,并给请求和响应添加了拦截器以实现自动的gzip解码,调用AsyncHttpRequest实例的get post等方法时最终会调用sendRequest方法,sendRequest方法接收httpClient、responseHandler、uriRequest等参数,在方法内部会构造请求的AsyncHttpRequest对象(newAsyncHttpRequest),并通过threadPool.submit(request)方法提交到线程池中,何为异步就体现在这里。
AsyncHttpRequest实现了Runnable接口,它的run方法就是核心代码,调用responseHandler.sendxxx 方法以实现各种方法回调和请求结果投递,在makeRequestWithRetries中有重试的逻辑,具体在retryHandler中有重试次数的判断,当重试次数超过最大值时(默认是5次),跳出while循环,这里重试的逻辑和Volley中的处理类似 。
其中AsyncHttpClient中默认的线程池没有核心线程,只有work线程,且工作线程的存活时间是60s,如果此种线程池不能满足需要,可以实现自己的线程池,并调用setThreadPool方法。
其中在调用AsyncHttpClient中各种请求方法时,会传入请求响应的各式xxxResponseHandler,针对不同的响应数据类型,有TextHttpResponseHandler、JsonHttpResponseHandler、FileHttpResponseHandler等,这些xxxResponseHandler中封装了Handler和Looper,因为构造Handler是需要先有Looper的,而looper的初始化是在AsyncHttpResponseHandler构造函数中,
this.looper = looper == null ? Looper.myLooper() : looper,即如果没有传入looper则使用当前线程的looper(即创建xxxResponseHandler的线程,可能是主线程也可能是子线程)。 这些xxxResponseHandler都继承自AsyncHttpResponseHandler类,并实现了
onSuccess(int statusCode, Header[] headers, byte[] responseBody) 和 onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error)方法,以处理不同返回数据类型的响应。
如上叙述印证了2 、3、4、10、11条结论。
------------------------------------------------------------------
class="brush:java;gutter:true;">AsyncHttpClient httpClient = new AsyncHttpClient(); RequestParams params = new RequestParams(); try { String filePath = getBaseContext().getExternalCacheDir().getPath() + File.separator + "IMG_20171106_202814.jpg"; File file = new File(filePath); if (file.exists()) { params.put("uploadimg", file, "image/jpeg"); } } catch (FileNotFoundException e) { e.printStackTrace(); } httpClient.setProxy("172.20.10.2", 8888); httpClient.post(this, "http://www.chuantu.biz/upload.php", /*headers,*/ params,/* null,*/ new TextHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, String responseBody) { printHeaders(headers); Log.d(TAG, responseBody); } @Override public void onFailure(int statusCode, Header[] headers, String responseBody, Throwable error) { } });
如上印证了5 、8 两条特性。
上传文件时,会调用RequestParams中的createMultipartEntity方法,其中SimpleMulitpartEntity的addPart方法会添加待写入流中的文件信息,之后将文件内容的字节写入到流中,具体见SimpleMultipartEntity的writeTo方法,其中SimpleMultipartEntity类实现了HttpEntity接口,其中重写了getContentType方法,此方法中返回标识性的header信息,Content-Type:multipart/form-data;boundary= xxxxxx, 分界线标识的字符串是在数字大小写字符等字符中随机抽取出来的30个字符组成。
需要注意到构造AsyncHttpRequest时最后的参数context, 如果context不为空,请求会被放到
Map中,以便在Activity onPause的时候或者onDestory的时候取消掉无用的请求等。
-------------------------------------------------------------------------------------------------------------------
BaseJsonHttpResponseHandler的使用
先添加Gson依赖,compile 'com.google.code.gson:gson:2.8.1'
这里以kuaidi100的快递数据为例:http://www.kuaidi100.com/query?type=xxx&postid=xxxx
先创建一个快递数据类的实体(这里字段并不全,只是为了说明问题,具体可以自行调试接口)
public class Express { public String message; public String nu; public int isCheck; public String com; public int status; public int state; public Express(String message, String nu, int isCheck, String com, int status, int state) { this.message = message; this.nu = nu; this.isCheck = isCheck; this.com = com; this.status = status; this.state = state; } @Override public String toString() { return "Express{" + "message='" + message + '\'' + ", nu='" + nu + '\'' + ", isCheck=" + isCheck + ", com='" + com + '\'' + ", status=" + status + ", state=" + state + '}'; } }
创建RequestParams 发起GET请求
RequestParams params = new RequestParams(); params.put("type", "shunfeng"); params.put("postid", "384566812983"); httpClient.get("http://www.kuaidi100.com/query", params, new BaseJsonHttpResponseHandler<Express>() { @Override public void onSuccess(int statusCode, Header[] headers, String rawJsonResponse, Express response) { Log.d(TAG, "response = " + response); } @Override public void onFailure(int statusCode, Header[] headers, Throwable throwable, String rawJsonData, Express errorResponse) { } @Override protected Express parseResponse(String rawJsonData, boolean isFailure) throws Throwable { Gson gson = new Gson(); return gson.fromJson(rawJsonData, Express.class); } });