查看: 2290|回复: 0

[Android教程] OkHttp自定义重试次数

发表于 2018-2-20 08:00:03

本文主要应用了OkHttp的Interceptor来实现自定义重试次数

虽然OkHttp自带retryOnConnectionFailure(true)方法可以实现重试,但是不支持自定义重试次数,所以有时并不能满足我们的需求。

#1.自定义重试拦截器:

  1. /**
  2. * 重试拦截器
  3. */
  4. public class RetryIntercepter implements Interceptor {
  5. public int maxRetry;//最大重试次数
  6. private int retryNum = 0;//假如设置为3次重试的话,则最大可能请求4次(默认1次+3次重试)
  7. public RetryIntercepter(int maxRetry) {
  8. this.maxRetry = maxRetry;
  9. }
  10. @Override
  11. public Response intercept(Chain chain) throws IOException {
  12. Request request = chain.request();
  13. System.out.println("retryNum=" + retryNum);
  14. Response response = chain.proceed(request);
  15. while (!response.isSuccessful() && retryNum < maxRetry) {
  16. retryNum++;
  17. System.out.println("retryNum=" + retryNum);
  18. response = chain.proceed(request);
  19. }
  20. return response;
  21. }
  22. }
复制代码

#2.测试场景类:

  1. 1 public class RetryTest {
  2. 2 String mUrl = "https://www.baidu.com/";
  3. 3 OkHttpClient mClient;
  4. 4
  5. 5 @Before
  6. 6 public void setUp() {
  7. 7 HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
  8. 8 logging.setLevel(HttpLoggingInterceptor.Level.BODY);
  9. 9
  10. 10 mClient = new OkHttpClient.Builder()
  11. 11 .addInterceptor(new RetryIntercepter(3))//重试
  12. 12 .addInterceptor(logging)//网络日志
  13. 13 .addInterceptor(new TestInterceptor())//模拟网络请求
  14. 14 .build();
  15. 15 }
  16. 16
  17. 17 @Test
  18. 18 public void testRequest() throws IOException {
  19. 19 Request request = new Request.Builder()
  20. 20 .url(mUrl)
  21. 21 .build();
  22. 22 Response response = mClient.newCall(request).execute();
  23. 23 System.out.println("onResponse:" + response.body().string());
  24. 24 }
  25. 25
  26. 26 class TestInterceptor implements Interceptor {
  27. 27
  28. 28 @Override
  29. 29 public Response intercept(Chain chain) throws IOException {
  30. 30 Request request = chain.request();
  31. 31 String url = request.url().toString();
  32. 32 System.out.println("url=" + url);
  33. 33 Response response = null;
  34. 34 if (url.equals(mUrl)) {
  35. 35 String responseString = "{\"message\":\"我是模拟的数据\"}";//模拟的错误的返回值
  36. 36 response = new Response.Builder()
  37. 37 .code(400)
  38. 38 .request(request)
  39. 39 .protocol(Protocol.HTTP_1_0)
  40. 40 .body(ResponseBody.create(MediaType.parse("application/json"), responseString.getBytes()))
  41. 41 .addHeader("content-type", "application/json")
  42. 42 .build();
  43. 43 } else {
  44. 44 response = chain.proceed(request);
  45. 45 }
  46. 46 return response;
  47. 47 }
  48. 48 }
  49. 49
  50. 50 }
复制代码

#3.输出结果:

  1. 1 retryNum=0
  2. 2 --> GET https://www.baidu.com/ HTTP/1.1
  3. 3 --> END GET
  4. 4 url=https://www.baidu.com/
  5. 5 <-- 400 null https://www.baidu.com/ (13ms)
  6. 6 content-type: application/json
  7. 7
  8. 8 {"message":"我是模拟的数据"}
  9. 9 <-- END HTTP (35-byte body)
  10. 10 retryNum=1
  11. 11 --> GET https://www.baidu.com/ HTTP/1.1
  12. 12 --> END GET
  13. 13 url=https://www.baidu.com/
  14. 14 <-- 400 null https://www.baidu.com/ (0ms)
  15. 15 content-type: application/json
  16. 16
  17. 17 {"message":"我是模拟的数据"}
  18. 18 <-- END HTTP (35-byte body)
  19. 19 retryNum=2
  20. 20 --> GET https://www.baidu.com/ HTTP/1.1
  21. 21 --> END GET
  22. 22 url=https://www.baidu.com/
  23. 23 <-- 400 null https://www.baidu.com/ (0ms)
  24. 24 content-type: application/json
  25. 25
  26. 26 {"message":"我是模拟的数据"}
  27. 27 <-- END HTTP (35-byte body)
  28. 28 retryNum=3
  29. 29 --> GET https://www.baidu.com/ HTTP/1.1
  30. 30 --> END GET
  31. 31 url=https://www.baidu.com/
  32. 32 <-- 400 null https://www.baidu.com/ (0ms)
  33. 33 content-type: application/json
  34. 34
  35. 35 {"message":"我是模拟的数据"}
  36. 36 <-- END HTTP (35-byte body)
  37. 37 onResponse:{"message":"我是模拟的数据"}
复制代码

#4.结果分析:
>1. 这里我用一个TestInterceptor拦截器拦截掉真实的网络请求,实现response.code的自定义
2. 在RetryIntercepter中,通过response.isSuccessful()来对响应码进行判断,循环调用了多次chain.proceed(request)来实现重试拦截
3. 从输出中可以看到,一共请求了4次(默认1次+重试3次)。

#5.其它实现方式
如果你是使用OkHttp+Retrofit+RxJava,你也可以使用retryWhen操作符:retryWhen(new RetryWithDelay())来实现重试机制

  1. 1 public class RetryWithDelay implements Func1<Observable<? extends Throwable>, Observable<?>> {
  2. 2
  3. 3 private final int maxRetries;
  4. 4 private final int retryDelayMillis;
  5. 5 private int retryCount;
  6. 6
  7. 7 public RetryWithDelay(int maxRetries, int retryDelayMillis) {
  8. 8 this.maxRetries = maxRetries;
  9. 9 this.retryDelayMillis = retryDelayMillis;
  10. 10 }
  11. 11
  12. 12 @Override
  13. 13 public Observable<?> call(Observable<? extends Throwable> attempts) {
  14. 14 return attempts
  15. 15 .flatMap(new Func1<Throwable, Observable<?>>() {
  16. 16 @Override
  17. 17 public Observable<?> call(Throwable throwable) {
  18. 18 if (++retryCount <= maxRetries) {
  19. 19 // When this Observable calls onNext, the original Observable will be retried (i.e. re-subscribed).
  20. 20 LogUtil.print("get error, it will try after " + retryDelayMillis + " millisecond, retry count " + retryCount);
  21. 21 return Observable.timer(retryDelayMillis,
  22. 22 TimeUnit.MILLISECONDS);
  23. 23 }
  24. 24 // Max retries hit. Just pass the error along.
  25. 25 return Observable.error(throwable);
  26. 26 }
  27. 27 });
  28. 28 }
  29. 29 }
复制代码



回复

使用道具 举报