Android xUtils3源码解析之网络模块
来源:互联网 发布:知乎匿名提问在哪里看 编辑:程序博客网 时间:2024/05/21 05:41
本文已授权微信公众号《非著名程序员》原创首发,转载请务必注明出处。
xUtils3源码解析系列
一. Android xUtils3源码解析之网络模块
二. Android xUtils3源码解析之图片模块
三. Android xUtils3源码解析之注解模块
四. Android xUtils3源码解析之数据库模块
关于xUtils3
- xUtils 包含了很多实用的android工具.
- xUtils 支持超大文件(超过2G)上传,更全面的http请求协议支持(11种谓词),拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响…
- xUtils 最低兼容Android 4.0 (api level 14). (Android 2.3?)
- xUtils3变化较多所以建立了新的项目不在旧版(github.com/wyouflf/xUtils)上继续维护, 相对于旧版本:
- HTTP实现替换HttpClient为UrlConnection, 自动解析回调泛型, 更安全的断点续传策略.
- 支持标准的Cookie策略, 区分domain, path…
- 事件注解去除不常用的功能, 提高性能.
- 数据库api简化提高性能, 达到和greenDao一致的性能.
- 图片绑定支持gif(受系统兼容性影响, 部分gif文件只能静态显示), webp; 支持圆角, 圆形, 方形等裁剪, 支持自动旋转…
xUtils3四大模块:网络请求、图片加载、ORM框架和事件注解。本文阅读分析网络请求相关代码。
使用版本:compile 'org.xutils:xutils:3.3.36'
xUtils3项目地址 : https://github.com/wyouflf/xUtils3
初始化
Ext.init(this);
public static class Ext { private static Application app; public static void init(Application app) { if (Ext.app == null) { Ext.app = app; } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
获取ApplicationCotext,方便以后调用。在Ext中有个静态代码块。详情如下:
public static class Ext { private static TaskController taskController; static { TaskControllerImpl.registerInstance(); // 默认信任所有https域名 HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }); } public static void setTaskController(TaskController taskController) { if (Ext.taskController == null) { Ext.taskController = taskController; } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
public static void registerInstance() { if (instance == null) { synchronized (TaskController.class) { if (instance == null) { instance = new TaskControllerImpl(); } } } x.Ext.setTaskController(instance); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
这段静态代码块的作用是注册TaskController对象为TaskControllerImpl实例。并设置信任所有https域名。ps:还是中文注释看着爽。
添加参数
RequestParams param = new RequestParams(url);param.addParameter("name","一口仨馍");
- 1
- 2
- 1
- 2
public RequestParams(String uri) { this(uri, null, null, null); } public RequestParams(String uri, ParamsBuilder builder, String[] signs, String[] cacheKeys) { if (uri != null && builder == null) { builder = new DefaultParamsBuilder(); } this.uri = uri; this.signs = signs; this.cacheKeys = cacheKeys; this.builder = builder; } public void addParameter(String name, Object value) { if (value == null) return; if (method == null || HttpMethod.permitsRequestBody(method)) { if (!TextUtils.isEmpty(name)) { if (value instanceof File || value instanceof InputStream || value instanceof byte[]) { this.fileParams.add(new KeyValue(name, value)); } else { if (value instanceof List) { ... } else if (value instanceof JSONArray) { ... } else if (value.getClass().isArray()) { ... } } else { this.bodyParams.add(new KeyValue(name, value)); } } } else { this.bodyContent = value.toString(); } } else { ... } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
这个时候还没有设置请求的方式,例如GET、POST等,所以mothod属性为null。而value为String类型的参数,所以name和value被以KeyValue结构的形式保存在bodyParams中。
网络请求
下文以x.http().post(requestParams, new Callback.CommonCallback<String>() {}
过程为例,逐步查看xUtils3调用流程。
x.http()
public static HttpManager http() { if (Ext.httpManager == null) { HttpManagerImpl.registerInstance(); } return Ext.httpManager; } public static void registerInstance() { if (instance == null) { synchronized (lock) { if (instance == null) { instance = new HttpManagerImpl(); } } } x.Ext.setHttpManager(instance); } public static void setHttpManager(HttpManager httpManager) { Ext.httpManager = httpManager; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
第一次调用的时候会初始化Ext#imageManager对象为HttpManagerImpl,以后所有HTTP/HTTPS相关调用都通过HttpManagerImpl管理。
HttpManagerImpl.post()
public final class HttpManagerImpl implements HttpManager { @Override public <T> Callback.Cancelable post(RequestParams entity, Callback.CommonCallback<T> callback) { return request(HttpMethod.POST, entity, callback); } @Override public <T> Callback.Cancelable request(HttpMethod method, RequestParams entity, Callback.CommonCallback<T> callback) { entity.setMethod(method); Callback.Cancelable cancelable = null; if (callback instanceof Callback.Cancelable) { cancelable = (Callback.Cancelable) callback; } HttpTask<T> task = new HttpTask<T>(entity, cancelable, callback); return x.task().start(task); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
这里以HttpMethod == HttpMethod.POST,entity为构造的请求参数,Callback.CommonCallback泛型为String查看流程。
首先设置RequestParams中请求方式为HttpMethod.POST,Callback.CommonCallback没有实现Callback.Cancelable接口,所以这里的if语句不成立,即cancelable为null。接下来构建HttpTask对象。跟进。
public class HttpTask<ResultType> extends AbsTask<ResultType> implements ProgressHandler { private static final PriorityExecutor HTTP_EXECUTOR = new PriorityExecutor(5, true); public HttpTask(RequestParams params, Callback.Cancelable cancelHandler, Callback.CommonCallback<ResultType> callback) { super(cancelHandler); this.params = params; this.callback = callback; if (callback instanceof Callback.CacheCallback) { this.cacheCallback = (Callback.CacheCallback<ResultType>) callback; } ... if (params.getExecutor() != null) { this.executor = params.getExecutor(); } else { if (cacheCallback != null) { this.executor = CACHE_EXECUTOR; } else { this.executor = HTTP_EXECUTOR; } } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
我们没有使用自定义的Executor(可以通过RequestParams.setExecutor()设置),所以params.getExecutor()返回是null,前文也提过CommonCallback没有实现CacheCallback,所以第一个if语句不成立,即cacheCallback为null。即,在HttpTask的构造函数中除了赋值params、callback之外,最主要的是指定了执行请求的线程池为HTTP_EXECUTOR。下面跟进看下这个HTTP_EXECUTOR。
FIFO线程池
public class PriorityExecutor implements Executor { private static final int CORE_POOL_SIZE = 5; private static final int MAXIMUM_POOL_SIZE = 256; private static final int KEEP_ALIVE = 1; private static final AtomicLong SEQ_SEED = new AtomicLong(0); private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); @Override public Thread newThread(Runnable runnable) { return new Thread(runnable, "xTID#" + mCount.getAndIncrement()); } }; /** * @param poolSize 工作线程数 * @param fifo 优先级相同时, 等待队列的是否优先执行先加入的任务. */ public PriorityExecutor(int poolSize, boolean fifo) { BlockingQueue<Runnable> mPoolWorkQueue = new PriorityBlockingQueue<Runnable>(MAXIMUM_POOL_SIZE, fifo ? FIFO_CMP : FILO_CMP); mThreadPoolExecutor = new ThreadPoolExecutor( poolSize, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, mPoolWorkQueue, sThreadFactory); } private static final Comparator<Runnable> FIFO_CMP = new Comparator<Runnable>() { @Override public int compare(Runnable lhs, Runnable rhs) { if (lhs instanceof PriorityRunnable && rhs instanceof PriorityRunnable) { PriorityRunnable lpr = ((PriorityRunnable) lhs); PriorityRunnable rpr = ((PriorityRunnable) rhs); int result = lpr.priority.ordinal() - rpr.priority.ordinal(); return result == 0 ? (int) (lpr.SEQ - rpr.SEQ) : result; } else { return 0; } } }; @Override public void execute(Runnable runnable) { if (runnable instanceof PriorityRunnable) { ((PriorityRunnable) runnable).SEQ = SEQ_SEED.getAndIncrement(); } mThreadPoolExecutor.execute(runnable); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
自定义了一个线程池,核心线程数是5,最大256,线程存活时间为1s,fifo(first in first out)类型。在执行Runnable之前,给PriorityRunnable的SEQ属性赋值(每次+1),并对比SEQ的值实现优先级。优先级相同时,SEQ值小的先执行。
初始化HttpTask之后,调用了x.task().start(task)
,x.task()返回Ext.taskController,实际返回是TaskControllerImpl对象,详见x$Ext中static代码块。所以实际上调用的是TaskControllerImpl.start()。
管理任务
public final class TaskControllerImpl implements TaskController { @Override public <T> AbsTask<T> start(AbsTask<T> task) { TaskProxy<T> proxy = null; if (task instanceof TaskProxy) { proxy = (TaskProxy<T>) task; } else { proxy = new TaskProxy<T>(task); } try { proxy.doBackground(); } catch (Throwable ex) { LogUtil.e(ex.getMessage(), ex); } return proxy; } /*package*/ TaskProxy(AbsTask<ResultType> task) { super(task); this.task = task; this.task.setTaskProxy(this); this.setTaskProxy(null); Executor taskExecutor = task.getExecutor(); if (taskExecutor == null) { taskExecutor = sDefaultExecutor; } this.executor = taskExecutor; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
任务代理
首先,将HttpTask包装成TaskProxy,然后执行TaskProxy.doBackground()。包装成TaskProxy对象的过程无非就是设置代理任务。ps:目前没看出这个TaskProxy存在的意义,只有一个HttpTask,难道是为了可拓展?重点看TaskProxy.doBackground()。
/*package*/ class TaskProxy<ResultType> extends AbsTask<ResultType> { @Override protected final ResultType doBackground() throws Throwable { this.onWaiting(); PriorityRunnable runnable = new PriorityRunnable( task.getPriority(), new Runnable() { @Override public void run() { try { // 等待过程中取消 if (callOnCanceled || TaskProxy.this.isCancelled()) { throw new Callback.CancelledException(""); } // start running TaskProxy.this.onStarted(); if (TaskProxy.this.isCancelled()) { // 开始时取消 throw new Callback.CancelledException(""); } // 执行task, 得到结果. task.setResult(task.doBackground()); TaskProxy.this.setResult(task.getResult()); // 未在doBackground过程中取消成功 if (TaskProxy.this.isCancelled()) { throw new Callback.CancelledException(""); } // 执行成功 TaskProxy.this.onSuccess(task.getResult()); } catch (Callback.CancelledException cex) { TaskProxy.this.onCancelled(cex); } catch (Throwable ex) { TaskProxy.this.onError(ex, false); } finally { TaskProxy.this.onFinished(); } } }); this.executor.execute(runnable); return null; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
this.onWaiting()的作用是将任务置为等待状态,对阅读代码无影响,继续。PriorityRunnable实现了Runnable接口,为传递进来的Runnable对象添加了priority属性,priority默认为3(优先级为0、1、2、3、4、5、6,数字越小,优先级越高)。之后会将PriorityRunnable添加进HTTP_EXECUTOR并依据优先级执行。callOnCanceled默认为false,之后设置任务状态为started,回调onStarted()方法。这些都不是重点,重点在下面两行:
// 执行task, 得到结果.task.setResult(task.doBackground());TaskProxy.this.setResult(task.getResult());
- 1
- 2
- 3
- 1
- 2
- 3
正室不死,代理终究还是代理。在这里调用了HttpTask.doBackground()。看样子真正的执行请求都在这里,跟进。
protected ResultType doBackground() throws Throwable { ... ResultType result = null; // 获取LoadType resolveLoadType(); // 创建真正的网络请求 request = createNewRequest(); ... // 是否重试,默认2次 boolean retry = true; // 已经重试的次数 int retryCount = 0; Throwable exception = null; HttpRetryHandler retryHandler = this.params.getHttpRetryHandler(); if (retryHandler == null) { retryHandler = new HttpRetryHandler(); } // 设置最大重试次数 retryHandler.setMaxRetryCount(this.params.getMaxRetryCount()); ... Object cacheResult = null; ... if (trustCache == null) { trustCache = false; } ... // 发起请求 retry = true; while (retry) { retry = false; try { if (this.isCancelled()) { throw new Callback.CancelledException("cancelled before request"); } // 由loader发起请求, 拿到结果. this.request.close(); // retry 前关闭上次请求 try { clearRawResult(); // 开始请求工作 LogUtil.d("load: " + this.request.getRequestUri()); requestWorker = new RequestWorker(); // 真正开始请求 requestWorker.request(); if (requestWorker.ex != null) { throw requestWorker.ex; } rawResult = requestWorker.result; } catch (Throwable ex) { clearRawResult(); i... } if (prepareCallback != null) { ... } else { result = (ResultType) rawResult; } ... } catch (HttpRedirectException redirectEx) { retry = true; LogUtil.w("Http Redirect:" + params.getUri()); } catch (Throwable ex) { switch (this.request.getResponseCode()) { case 204: // empty content case 205: // empty content case 304: // disk cache is valid. return null; default: { exception = ex; if (this.isCancelled() && !(exception instanceof Callback.CancelledException)) { exception = new Callback.CancelledException("canceled by user"); } retry = retryHandler.canRetry(this.request, exception, ++retryCount); } } } } if (exception != null && result == null && !trustCache) { hasException = true; throw exception; } return result; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
有些长,我们一点点的看。首先,ResultType肯定是我们传递进来的泛型String。resolveLoadType()为loadType赋值,港真,这里的loadType和ResultType是一样的。没搞明白为什么ResultType能解决的事情,又定义了一个loadType属性。难道是为了好区分ResultType是要返回的类型,loadType是要解析的类型?实际上两者是一样的,在这里都是String。非要说区别的话,ResultType是String,loadType为String.class。
请求参数的处理
// 初始化请求参数 private UriRequest createNewRequest() throws Throwable { // init request params.init(); UriRequest result = UriRequestFactory.getUriRequest(params, loadType); result.setCallingClassLoader(callback.getClass().getClassLoader()); result.setProgressHandler(this); this.loadingUpdateMaxTimeSpan = params.getLoadingUpdateMaxTimeSpan(); this.update(FLAG_REQUEST_CREATED, result); return result; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
在params.init()中,主要是设置信任所有证书。主要关注点在下面的创建UriRequest对象。
public static UriRequest getUriRequest(RequestParams params, Type loadType) throws Throwable { // get scheme String scheme = null; String uri = params.getUri(); int index = uri.indexOf(":"); if (index > 0) { scheme = uri.substring(0, index); } else if (uri.startsWith("/")) { scheme = "file"; } // get UriRequest if (!TextUtils.isEmpty(scheme)) { Class<? extends UriRequest> cls = SCHEME_CLS_MAP.get(scheme); if (cls != null) { Constructor<? extends UriRequest> constructor = cls.getConstructor(RequestParams.class, Class.class); return constructor.newInstance(params, loadType); } else { if (scheme.startsWith("http")) { return new HttpRequest(params, loadType); } else if (scheme.equals("assets")) { return new AssetsRequest(params, loadType); } else if (scheme.equals("file")) { return new LocalFileRequest(params, loadType); } else { throw new IllegalArgumentException("The url not be support: " + uri); } } } else { throw new IllegalArgumentException("The url not be support: " + uri); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
获取scheme,这里以https分析。这里好像还整个缓存Map,不管有没有缓存,返回的都是HttpRequest对象,只是来源不一样,这里就不具体分析这个存取的过程。实例化HttpRequest的时候,还有些文章。下面跟进。
public class HttpRequest extends UriRequest { /*package*/ HttpRequest(RequestParams params, Type loadType) throws Throwable { super(params, loadType); }}public abstract class UriRequest implements Closeable { protected final Loader<?> loader; /*package*/ UriRequest(RequestParams params, Type loadType) throws Throwable { this.params = params; this.queryUrl = buildQueryUrl(params); this.loader = LoaderFactory.getLoader(loadType, params); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
运用工厂模式,通过LoaderFactory获取了一个Loader对象,这个对象在后面有很大的作用。先跟进看下。
public final class LoaderFactory { private LoaderFactory() { } private static final HashMap<Type, Loader> converterHashMap = new HashMap<Type, Loader>(); static { converterHashMap.put(String.class, new StringLoader()); ... } @SuppressWarnings("unchecked") public static Loader<?> getLoader(Type type, RequestParams params) { Loader<?> result = converterHashMap.get(type); if (result == null) { result = new ObjectLoader(type); } else { result = result.newInstance(); } result.setParams(params); return result; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
传递进来的type为String.class,所以调用StringLoader.newInstance()。这里并不是反射,newInstance()只是个普通方法,返回StringLoader对象。拓展的有些远了,回到HttpTask.doBackground()。大概屡一下思路:现在已经将解析出loadType为String.class,HttpRequest对象赋值给request,并在在实例化HttpRequest对象的过程中设置Loader
retry机制
在HttpTask.doBackground()中定义了一个局部变量retry,默认为true。并通过retryHandler.setMaxRetryCount(this.params.getMaxRetryCount())
设置retry数量为2(默认)。white(retry)
中首先把retry设置为false,即“期望”一次请求成功。如果中途出现HttpRedirectException异常或者抛出Throwable并且responseCode不等于204、205、304,那么会再执行一遍while循环。其中HttpRedirectException异常是无限次retry(这点感觉还是计数要好一些),抛出Throwable才会对retry次数进行处理。下面是整个流程的分析。
// 发起请求 retry = true; while (retry) { retry = false; ... try { requestWorker = new RequestWorker(); requestWorker.request(); if (requestWorker.ex != null) { throw requestWorker.ex; } } catch (Throwable ex) { ... throw ex; } ... } catch (HttpRedirectException redirectEx) { retry = true; LogUtil.w("Http Redirect:" + params.getUri()); } catch (Throwable ex) { switch (this.request.getResponseCode()) { case 204: // empty content case 205: // empty content case 304: // disk cache is valid. return null; default: { ... retry = retryHandler.canRetry(this.request, exception, ++retryCount); } } } } private final class RequestWorker { /*private*/ Object result; /*private*/ Throwable ex; private RequestWorker() { } public void request() { try { ... try { this.result = request.loadResult(); } catch (Throwable ex) { this.ex = ex; } if (this.ex != null) { throw this.ex; } } catch (Throwable ex) { this.ex = ex; ... if (errorCode == 301 || errorCode == 302) {//重定向 HttpTask.this.params = redirectParams; HttpTask.this.request = createNewRequest(); this.ex = new HttpRedirectException(errorCode, httpEx.getMessage(), httpEx.getResult()); } } finally { ... } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
正常的请求失败,会通过retryHandler.canRetry(),将retry置为true,最多执行两次retry。让我疑惑的地方在于重定向的处理。在requestWorker.request()中,如果有重定向,会抛出HttpRedirectException。但是在HttpTask#doBackground()中
try { if (requestWorker.ex != null) { throw requestWorker.ex; } } catch (Throwable ex) { clearRawResult(); if (this.isCancelled()) { throw new Callback.CancelledException("cancelled during request"); } else { throw ex; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
这里向上转型为Throwable并抛出,从而进入外层的
} catch (HttpRedirectException redirectEx) { retry = true; LogUtil.w("Http Redirect:" + params.getUri()); } catch (Throwable ex) { switch (this.request.getResponseCode()) { case 204: // empty content case 205: // empty content case 304: // disk cache is valid. return null; default: { exception = ex; if (this.isCancelled() && !(exception instanceof Callback.CancelledException)) { exception = new Callback.CancelledException("canceled by user"); } retry = retryHandler.canRetry(this.request, exception, ++retryCount); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
正常应该进入HttpRedirectException的,但是向上转型成Throwable之后就只能进入下面的catch代码块中。那么HttpRedirectException存在的意义在哪里?希望明白的给指点下。
真正的请求
requestWorker = new RequestWorker();requestWorker.request();
- 1
- 2
- 1
- 2
HttpTask.doBackground()中请求其实只有这两行代码。RequestWorker是HttpTask的一个final内部类,requestWorker.request()方法内部会设置拦截器,处理重定向等,这些暂时不是关注的重点。总之先把流程跑通再说。
private final class RequestWorker { /*private*/ Object result; public void request() { ... this.result = request.loadResult(); ... } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
request实际上是HttpRequest对象。
public class HttpRequest extends UriRequest { @Override public Object loadResult() throws Throwable { isLoading = true; return super.loadResult(); }}public abstract class UriRequest implements Closeable { public Object loadResult() throws Throwable { return this.loader.load(this); }}/*package*/ class StringLoader extends Loader<String> { @Override public String load(final UriRequest request) throws Throwable { request.sendRequest(); return this.load(request.getInputStream()); } @Override public String load(final InputStream in) throws Throwable { resultStr = IOUtil.readStr(in, charset); return resultStr; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
经过层层调用最终调用request.sendRequest(),即HttpRequest.sendRequest()。看方法名字也知道干撒的了,代码太长这里就不贴了,概述下主要作用:依据之前的各种参数设置请求,发起请求,获取返回状态码,如果有自定义拦截器的话,还会调用beforeRequest()、afterRequest()。接下来调用request.getInputStream()获取输入流,并使用IOUtil.readStr()转换之后返回String,最后在RequestWorker.request()中将返回的String赋值给result。一切顺利的话,接着回到Task.doBackground()。执行task.setResult(task.doBackground())
。之后翻来覆去的调用get/setResult好像暂时没有用,可能是其他情况下的处理吧。不过也没有什么影响,接着会调用TaskProxy.this.onSuccess(task.getResult())
。在这个方法中通过Handler(获取了MainLooper)在主线程中调用callback.onSuccess(result)
。如果出现异常会则调用TaskProxy.this.onError(ex, false)
,不管成功还是失败都会调用finally中的TaskProxy.this.onFinish(ex, false)
过程都是类似的,这里就不再赘述。至此,整个网络请求包括回调结束。
取消网络请求
取消网络请求会调用cancelable.cancel()
,这里的cancelable是HttpManagerImpl.request()返回的TaskProxy对象。即等价于执行TaskProxy.cancle()。这个方法的具体实现在父类AbsTask中。
@Override public final synchronized void cancel() { if (!this.isCancelled) { this.isCancelled = true; cancelWorks(); if (cancelHandler != null && !cancelHandler.isCancelled()) { cancelHandler.cancel(); } if (this.state == State.WAITING || (this.state == State.STARTED && isCancelFast())) { if (taskProxy != null) { taskProxy.onCancelled(new Callback.CancelledException("cancelled by user")); taskProxy.onFinished(); } else if (this instanceof TaskProxy) { this.onCancelled(new Callback.CancelledException("cancelled by user")); this.onFinished(); } } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
AbsTask实现了Cancelable接口,所以这里的cancelHandler不为null,但是cancelHandler.isCancelled()返回true,所以不会循环调用cancelHandler.cancel()。任务被创建后就进入了WAITING状态,所以会调用TaskProxy.onCancelled()和TaskProxy.onFinished()。在这两个回调方法中分别通过Hanlder在主线程中调用HttpTask的onCanclled()和onFinished()方法,之后再调用接口回调中的onCanclled()和onFinished()方法。需要注意的是HttpTask.onFinished()方法。
protected void onFinished() { if (tracker != null) { tracker.onFinished(request); } x.task().run(new Runnable() { @Override public void run() { closeRequestSync(); } }); callback.onFinished(); } private void closeRequestSync() { clearRawResult(); IOUtil.closeQuietly(request); } IoUtil# public static void closeQuietly(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (Throwable ignored) { LogUtil.d(ignored.getMessage(), ignored); } } } HttpRequest# public void close() throws IOException { if (inputStream != null) { IOUtil.closeQuietly(inputStream); inputStream = null; } if (connection != null) { connection.disconnect(); //connection = null; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
在调用callback.onFinished()的同时异步执行线程,清除请求结果和关闭链接。这个过程对调用者来说是异步的无感知的。
总结
- xUtils3使用PriorityExecutor(FIFO线程池)+PriorityRunnable(带优先级的Runnable)实现网络请求。
- 通过传入MainLooper的Handler实现由子线程到主线程的切换,并调用相应的回调方法。
- 支持retry,默认2次。
- 通过给Task设置不同状态,实现不同状态下的处理,主要是为了实现cancle()。
- 自带拓展了不同类型的Callback和Loader,满足日常开发(特殊需求可仿照实现)。
- Android xUtils3源码解析之网络模块
- Android xUtils3源码解析之注解模块
- Android xUtils3源码解析之数据库模块
- Android xUtils3源码解析之图片模块
- Android xUtils3源码解析之注解模块
- Android xUtils3源码解析之数据库模块
- Android高级学习之xUtils3源码解析
- Android xUtils3完全解析
- Android xUtils3完全解析
- Android xUtils3完全解析
- Android--Xutils3源码案例调试
- Android xUtils3.0框架解析
- android Xutils3网络请求封装
- Android-网络框架02XUtils3
- xUtils3.0使用介绍:网络模块
- Android FM模块学习之四源码解析(一)
- Android FM模块学习之四源码解析(二)
- Android FM模块学习之四源码解析(三)
- LeakCanary——直白的展现Android中的内存泄露
- 序列化与反序列化
- -Mastering KVM Virtualization-:第三章 搭建独立的KVM虚拟化
- ContentProvider模板
- 15.2-全栈Java笔记:ActionEvent事件类型可以实现哪些功能?
- Android xUtils3源码解析之网络模块
- android 多线程实现方式
- 测试1
- 定位深入理解CSS定位中的偏移
- for循环打印金字塔
- 使用logstash将kafka数据入到elasticsearch
- Qt Designer中利用各个控件来setStyleSheet
- 对象,原型,原型链
- SpringMVC +Maven