Skip to content

Commit dff5a6c

Browse files
committed
http retry support
1 parent 9d08d94 commit dff5a6c

File tree

3 files changed

+57
-10
lines changed

3 files changed

+57
-10
lines changed

src/com/loopj/android/http/AsyncHttpClient.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.io.IOException;
2222
import java.io.InputStream;
23+
import java.util.concurrent.Executor;
2324
import java.util.concurrent.ExecutorService;
2425
import java.util.concurrent.Executors;
2526
import java.util.zip.GZIPInputStream;
@@ -56,6 +57,7 @@
5657
public class AsyncHttpClient {
5758
public static final int DEFAULT_MAX_CONNECTIONS = 10;
5859
public static final int DEFAULT_SOCKET_TIMEOUT = 30 * 1000;
60+
public static final int DEFAULT_MAX_RETRIES = 5;
5961
private static final String ENCODING = "UTF-8";
6062
private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
6163
private static final String ENCODING_GZIP = "gzip";
@@ -65,7 +67,7 @@ public class AsyncHttpClient {
6567

6668
private DefaultHttpClient httpClient;
6769
private HttpContext httpContext;
68-
private ExecutorService threadPool;
70+
private Executor threadPool;
6971

7072
public AsyncHttpClient(String userAgent) {
7173
BasicHttpParams httpParams = new BasicHttpParams();
@@ -110,12 +112,18 @@ public void process(HttpResponse response, HttpContext context) {
110112
}
111113
}
112114
});
115+
116+
httpClient.setHttpRequestRetryHandler(new RetryHandler(DEFAULT_MAX_RETRIES));
113117
}
114118

115119
public void setCookieStore(CookieStore cookieStore) {
116120
httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
117121
}
118122

123+
public void setThreadPool(Executor threadPool) {
124+
this.threadPool = threadPool;
125+
}
126+
119127
public void get(String url, AsyncHttpResponseHandler responseHandler) {
120128
get(url, null, responseHandler);
121129
}

src/com/loopj/android/http/AsyncHttpRequest.java

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,23 @@
1919
package com.loopj.android.http;
2020

2121
import java.io.IOException;
22+
import java.net.ConnectException;
2223

2324
import org.apache.http.HttpResponse;
2425
import org.apache.http.client.HttpClient;
26+
import org.apache.http.client.HttpRequestRetryHandler;
2527
import org.apache.http.client.methods.HttpUriRequest;
28+
import org.apache.http.impl.client.AbstractHttpClient;
2629
import org.apache.http.protocol.HttpContext;
2730

2831
public class AsyncHttpRequest implements Runnable {
29-
private HttpClient client;
32+
private AbstractHttpClient client;
3033
private HttpContext context;
3134
private HttpUriRequest request;
3235
private AsyncHttpResponseHandler responseHandler;
36+
private int executionCount;
3337

34-
public AsyncHttpRequest(HttpClient client, HttpContext context, HttpUriRequest request, AsyncHttpResponseHandler responseHandler) {
38+
public AsyncHttpRequest(AbstractHttpClient client, HttpContext context, HttpUriRequest request, AsyncHttpResponseHandler responseHandler) {
3539
this.client = client;
3640
this.context = context;
3741
this.request = request;
@@ -44,10 +48,10 @@ public void run() {
4448
responseHandler.sendStartMessage();
4549
}
4650

47-
HttpResponse response = client.execute(request, context);
51+
makeRequestWithRetries();
52+
4853
if(responseHandler != null) {
4954
responseHandler.sendFinishMessage();
50-
responseHandler.sendResponseMessage(response);
5155
}
5256
} catch (IOException e) {
5357
if(responseHandler != null) {
@@ -56,4 +60,39 @@ public void run() {
5660
}
5761
}
5862
}
63+
64+
private void makeRequest() throws IOException {
65+
HttpResponse response = client.execute(request, context);
66+
if(responseHandler != null) {
67+
responseHandler.sendResponseMessage(response);
68+
}
69+
}
70+
71+
private void makeRequestWithRetries() throws ConnectException {
72+
// This is an additional layer of retry logic lifted from droid-fu
73+
// See: https://github.com/kaeppler/droid-fu/blob/master/src/main/java/com/github/droidfu/http/BetterHttpRequestBase.java
74+
boolean retry = true;
75+
IOException cause = null;
76+
HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler();
77+
while (retry) {
78+
try {
79+
makeRequest();
80+
return;
81+
} catch (IOException e) {
82+
cause = e;
83+
retry = retryHandler.retryRequest(cause, ++executionCount, context);
84+
} catch (NullPointerException e) {
85+
// there's a bug in HttpClient 4.0.x that on some occasions causes
86+
// DefaultRequestExecutor to throw an NPE, see
87+
// http://code.google.com/p/android/issues/detail?id=5255
88+
cause = new IOException("NPE in HttpClient" + e.getMessage());
89+
retry = retryHandler.retryRequest(cause, ++executionCount, context);
90+
}
91+
}
92+
93+
// no retries left, crap out with exception
94+
ConnectException ex = new ConnectException();
95+
ex.initCause(cause);
96+
throw ex;
97+
}
5998
}

src/com/loopj/android/http/PersistentCookieStore.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public List<Cookie> getCookies() {
127127
return new ArrayList<Cookie>(cookies.values());
128128
}
129129

130-
private static String encodeCookie(SerializableCookie cookie) {
130+
protected String encodeCookie(SerializableCookie cookie) {
131131
ByteArrayOutputStream os = new ByteArrayOutputStream();
132132
try {
133133
ObjectOutputStream outputStream = new ObjectOutputStream(os);
@@ -139,7 +139,7 @@ private static String encodeCookie(SerializableCookie cookie) {
139139
return byteArrayToHexString(os.toByteArray());
140140
}
141141

142-
private static Cookie decodeCookie(String cookieStr) {
142+
protected Cookie decodeCookie(String cookieStr) {
143143
byte[] bytes = hexStringToByteArray(cookieStr);
144144
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
145145
Cookie cookie = null;
@@ -154,8 +154,8 @@ private static Cookie decodeCookie(String cookieStr) {
154154
}
155155

156156
// Using some super basic byte array <-> hex conversions so we don't have
157-
// to rely on any large Base64 libraries
158-
private static String byteArrayToHexString(byte[] b) {
157+
// to rely on any large Base64 libraries. Can be overridden if you like!
158+
protected String byteArrayToHexString(byte[] b) {
159159
StringBuffer sb = new StringBuffer(b.length * 2);
160160
for(int i=0; i<b.length; i++) {
161161
int v = b[i] & 0xff;
@@ -167,7 +167,7 @@ private static String byteArrayToHexString(byte[] b) {
167167
return sb.toString().toUpperCase();
168168
}
169169

170-
private static byte[] hexStringToByteArray(String s) {
170+
protected byte[] hexStringToByteArray(String s) {
171171
int len = s.length();
172172
byte[] data = new byte[len / 2];
173173
for(int i=0; i<len; i+=2) {

0 commit comments

Comments
 (0)