Async Http Connection
源碼地址: https://github.com/chenyoca/async-http-connection
- a multithread callback-based async http connection library. it can be use on android project or general java project.
- 一個基於回調機制的多線程異步Http連接庫。它可用於Android項目或者一般Java項目。
適用
Async HTTP Connection爲簡單的Http連接請求而設計。適用於API SDK等小數據傳輸項目,設計目標爲Android項目。
當前項目屬性爲Java項目,並使用JUnit4作爲測試環境,主要是Android項目調試不方便。
如果需要完善的功能,推薦一位國外大神的項目:[android-async-http](https://github.com/loopj/android-async-http)
特點
- 簡單 提供POST和GET兩個接口,通過擴展接口可設置PUT、DELETE方法。通過參數和回調接口完成整個Http連接的交互。
- 輕量 純JDK實現,不依賴第三方Jar包。
- 快速 採用Executor多線程併發框架,秉承它的併發處理優勢。
- 可擴展 框架提供Invoker擴展,通過實現RequestInvoker可方便的把HttpClient等優秀框架整合到項目中。
測試輔助
在多線程測試中,如果併發多條線程,則測試主線程需要等待所在測試子線程全部返回後才結束。一般採用兩種方式:1、Thread.sleep()方式。2、CountDown計數方式。
所有問題的的解決方式都不只有一種,看誰的方式更好更——優雅而已。
比如:本框架內置多線程測試輔助工具組合 ResponseCallbackTrace + ThreadWaiter。可以利用簡單的幾個方法,就解決併發線程等待的問題。
多線程測試輔助的使用方法
使用方法很簡單
- 創建回調接口動態代理
protected final ResponseCallbackTrace callbackTrace = new ResponseCallbackTrace();
ResponseCallbackTrace 是一個動態代理實現類,它可以監聽 ResponseCallback 的調用。並將線程執行情況記錄在ThreadWaiter中。
- 對回調接口添加代理
for(String url : urls){
http.get(url, null,
// 使用回調動態代理,可以自動處理等待其它線程返回的問題
callbackTrace.trace(callback));
}
- 等待所有線程返回
//等待所有線程返回
ThreadWaiter.waitingThreads();
完整的測試代碼
public class UrlsTestCase{
final static String[] AvailableUrls = {
"http://www.lurencun.com",
"http://www.163.com",
"http://www.126.com",
"http://www.google.com.hk",
"http://www.qq.com",
"http://www.ifeng.com",
"http://www.renren.com",
"http://www.58.com",
"http://www.psbc.com",
"http://www.suning.com",
"http://www.jumei.com",
"http://www.xiu.com",
"http://www.letv.com",
"http://www.miercn.com",
"http://www.jrj.com",
"http://www.suning.com",
"http://www.9ku.com",
"http://www.jumei.com",
"http://www.ctrip.com",
"http://www.tuniu.com",
"http://www.icbc.com",
"http://www.ccb.com",
"http://www.gexing.com",
"http://www.nipic.com",
"http://www.jxedt.com",
"http://www.iqiyi.com",
"http://www.skycn.com",
"http://www.7k7k.com",
};
protected ResponseCallback callback = new ResponseCallback() {
@Override
public void onResponse(InputStream response,URL url) {
System.out.println("[test GET] --> response back, url = "+url);
Assert.assertNotNull(response);
}
@Override
public void onError(Throwable exp) {
Assert.fail(exp.getMessage());
System.err.println("[test GET] --> response error");
}
@Override
public void onSubmit(URL url,ParamsWrapper params) {}
@Override
public void onResponseWithToken(InputStream response, URL url, Object token) {}
};
final AsyncHttpConnection http = AsyncHttpConnection.getInstance();
final ResponseCallbackTrace callbackTrace = new ResponseCallbackTrace();
@Test
public final void test(){
testAllUrls(AvailableUrls);
//等待所有線程返回
ThreadWaiter.waitingThreads();
}
protected void testAllUrls(String[] urls){
for(String url : urls){
http.get(url, null,
// 使用回調動態代理,可以自動處理等待其它線程返回的問題
callbackTrace.trace(callback));
}
}
}
使用
默認使用SimpleHttpInvoker類執行Http連接,基於HttpUrlConnection實現。 提供兩個接口實現類:BinaryResponseHandler、StringResponseHandler。分別處理二進制數據和字符數據。
更多例子見源目錄的 test 目錄
簡單的例子
//使用Get方法,取得服務端響應流:
AsyncHttpConnection http = AsyncHttpConnection.getInstance();
ParamsWrapper params = ...;
String url = ...
// callback with InputStream
int requestId = http.get(url, params, new ResponseCallback() {
@Override
public void onResponse(InputStream response,URL url) {
System.out.println("[test GET] --> response back, url = "+url);
Assert.assertNotNull(response);
}
@Override
public void onError(Throwable exp) {
System.err.println("[test GET] --> response error, url = "+url);
}
@Override
public void onSubmit(URL url,ParamsWrapper params) {
}
});
// callback with String
int requestId2 = http.get(url, null, new StringResponseHandler() {
@Override
public void onSubmit(URL url,ParamsWrapper params) {
}
@Override
public void onError(Throwable exp) {
exp.printStackTrace();
requestBack();
}
@Override
public void onResponse(String content, URL url) {
System.out.println("content->"+content);
requestBack();
}
});
// callback with Binary
http.get(url, null, new BinaryResponseHandler() {
@Override
public void onSubmit(URL url, ParamsWrapper params) {
}
@Override
public void onError(Throwable exp) {
exp.printStackTrace();
requestBack();
}
@Override
public void onResponse(byte[] data, URL url) {
final int size = 4465;
Assert.assertEquals(size, data.length);
System.out.println("Data size -> "+String.valueOf(data.length));
requestBack();
}
});
//使用POST方法,取得服務端響應流:
AsyncHttpConnection http = AsyncHttpConnection.getInstance();
ParamsWrapper params = ...;
String url = ...
// callback with Stream
int requestId = http.post(url, params, new ResponseCallback() {
@Override
public void onResponse(InputStream response,URL url) {
System.out.println("[test POST] --> response back, url = "+url);
Assert.assertNotNull(response);
requestBack();
}
@Override
public void onError(Throwable exp) {
System.err.println("[test POST] --> response error, url = "+url);
requestBack();
}
@Override
public void onSubmit(URL url) {
}
});
// callback with String
http.post(url, params, new StringResponseHandler() {
@Override
public void onSubmit(URL url,ParamsWrapper params) {
System.out.println(">> target: "+url.getHost()+" --> "+url.getPath());
}
@Override
public void onError(Throwable exp) {
exp.printStackTrace();
}
@Override
public void onResponse(String content, URL url) {
System.out.println("Return -> \n"+content);
}
});
更詳細的例子
//使用POST方法,取得服務端響應流:
AsyncHttpConnection http = AsyncHttpConnection.getInstance();
final int KEY_VAL = 24;
ParamsWrapper params = new ParamsWrapper();
params.put("firstname", "chen");
params.put("lastname", "yoca");
params.put("foo", KEY_VAL);
params.put("cookiename", KEY_VAL);
params.put("cookievalue", KEY_VAL);
int requestId = http.post(url, params, new StringResponseHandler() {
@Override
public void onSubmit(URL url) {
System.out.println(">> target: "+url.getHost()+" --> "+url.getPath());
}
@Override
public void onError(Throwable exp) {
requestBack();
exp.printStackTrace();
}
@Override
public void onResponse(String content, URL url) {
Assert.assertNotNull(content);
boolean containsKey = content.contains(String.valueOf(KEY_VAL));
Assert.assertEquals(true, containsKey);
requestBack();
}
});
// 在大量併發的異步請求情況下,每個請求的回調可能需要一個標識碼來標記這個回調結果。
// 有兩種方式來解決這個問題:
// 1、使用get和post返回的RequestID來標識,但這需要對RequestID進行管理
// 2、使用get和post的token參數
AsyncHttpConnection http = AsyncHttpConnection.getInstance();
final int KEY_VAL = 24;
ParamsWrapper params = new ParamsWrapper();
params.put("firstname", "chen");
params.put("lastname", "yoca");
params.put("foo", KEY_VAL);
params.put("cookiename", KEY_VAL);
params.put("cookievalue", KEY_VAL);
// ******** 利用token 接口 ************
Object token = "1234566";
// 如果調用了帶token的方法,回調的方法將是onResponse(String content, URL url, Object token)
int requestId = http.post(url, params, token, new StringResponseHandler() {
@Override
public void onSubmit(URL url) {
System.out.println(">> target: "+url.getHost()+" --> "+url.getPath());
}
@Override
public void onError(Throwable exp) {
requestBack();
exp.printStackTrace();
}
@Override
public void onResponse(String content, URL url, Object token) {
// token == "1234566" Token被傳到這裏作爲標識
Assert.assertNotNull(content);
boolean containsKey = content.contains(String.valueOf(KEY_VAL));
Assert.assertEquals(true, containsKey);
requestBack();
}
});
HTTP Method
需要使用其它Http Mehtod,可以通過
* sendRequest(String url,ParamsWrapper params,HttpMethod method,Object token,ResponseCallback callback)
* sendRequest(String url,ParamsWrapper params,HttpMethod method, ResponseCallback callback)
接口調用。