本文已授权微信公众号《非著名程序猿》原创首发,转载请务必注明出处。

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)上继续维护, 相对于旧版本号:
    1. HTTP实现替换HttpClient为UrlConnection, 自己主动解析回调泛型, 更安全的断点续传策略.
    2. 支持标准的Cookie策略, 区分domain, path…
    3. 事件注解去除不经常使用的功能, 提高性能.
    4. 数据库api简化提高性能, 达到和greenDao一致的性能.
    5. 图片绑定支持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;
}
}
}

获取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;
}
}
}
    public static void registerInstance() {
if (instance == null) {
synchronized (TaskController.class) {
if (instance == null) {
instance = new TaskControllerImpl();
}
}
}
x.Ext.setTaskController(instance);
}

这段静态代码块的作用是注冊TaskController对象为TaskControllerImpl实例。

并设置信任全部https域名。ps:还是中文凝视看着爽。

加入參数

RequestParams param = new RequestParams(url);
param.addParameter("name","一口仨馍");
    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 {
...
}
}

这个时候还没有设置请求的方式,比如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;
}

第一次调用的时候会初始化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);
}
}

这里以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;
}
}
}
}

我们没有使用自己定义的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);
}
}

自己定义了一个线程池,核心线程数是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;
}
}

任务代理

首先。将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;
}
}

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());

正室不死,代理终究还是代理。在这里调用了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;
}

有些长,我们一点点的看。

首先,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;
}

在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);
}
}

获取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);
}
}

运用工厂模式,通过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;
}
}

传递进来的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 {
...
}
}
}

正常的请求失败,会通过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;
}
}

这里向上转型为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);
}
}
}

正常应该进入HttpRedirectException的。可是向上转型成Throwable之后就仅仅能进入以下的catch代码块中。

那么HttpRedirectException存在的意义在哪里?希望明确的给指点下。

真正的请求

requestWorker = new RequestWorker();
requestWorker.request();

HttpTask.doBackground()中请求事实上仅仅有这两行代码。RequestWorker是HttpTask的一个final内部类。requestWorker.request()方法内部会设置拦截器,处理重定向等,这些临时不是关注的重点。

总之先把流程跑通再说。

    private final class RequestWorker {
/*private*/ Object result;
public void request() {
...
this.result = request.loadResult();
...
}
}

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;
}
}

经过层层调用终于调用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();
}
}
}
}

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;
}
}

在调用callback.onFinished()的同一时候异步运行线程。清除请求结果和关闭链接。这个过程对调用者来说是异步的无感知的。

总结

  1. xUtils3使用PriorityExecutor(FIFO线程池)+PriorityRunnable(带优先级的Runnable)实现网络请求。

  2. 通过传入MainLooper的Handler实现由子线程到主线程的切换,并调用对应的回调方法。
  3. 支持retry,默认2次。
  4. 通过给Task设置不同状态,实现不同状态下的处理,主要是为了实现cancle()。
  5. 自带拓展了不同类型的Callback和Loader,满足日常开发(特殊需求可仿照实现)。

Android xUtils3源代码解析之网络模块的更多相关文章

  1. Android EventBus源代码解析 带你深入理解EventBus

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus ...

  2. Android DiskLruCache 源代码解析 硬盘缓存的绝佳方案

    转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/47251585: 本文出自:[张鸿洋的博客] 一.概述 依然是整理东西.所以最近 ...

  3. Android Xutils3 完全解析

    1.先来认识一下xUtils3 1)xUtils3简介 xUtils是基于Afinal开发的目前功能比较完善的一个Android开源框架,最近又发布了xUtil3.0,在增加新功能的同时又提高了框架的 ...

  4. 源代码解析Android中View的layout布局过程

    Android中的Veiw从内存中到呈如今UI界面上须要依次经历三个阶段:量算 -> 布局 -> 画图,关于View的量算.布局.画图的整体机制可參见博文 < Android中Vie ...

  5. Android View体系(八)从源代码解析View的layout和draw流程

    相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源 ...

  6. Android SVG动画PathView源代码解析与使用教程(API 14)

    使用的是一个第三方库android-pathview主要是一个自己定义View--PathView.跟全部自己定义View一样,重写了三个构造方法. 而且终于调用三个參数的构造方法,在里面获取自己定义 ...

  7. Android源代码解析之(四)--&gt;HandlerThread

    转载请标明出处:一片枫叶的专栏 上一篇文章中我们解说了AsyncTast的基本使用以及实现原理,我们知道AsyncTask内部是通过线程池和Handler实现的.通过对线程池和handler的封装实现 ...

  8. Android源代码解析之(六)--&gt;Log日志

    转载请标明出处:一片枫叶的专栏 首先说点题外话,对于想学android framework源代码的同学,事实上能够在github中fork一份,详细地址:platform_frameworks_bas ...

  9. Android源代码解析之(三)--&gt;异步任务AsyncTask

    转载请标明出处:一片枫叶的专栏 上一篇文章中我们解说了android中的异步消息机制. 主要解说了Handler对象的使用方式.消息的发送流程等.android的异步消息机制是android中多任务处 ...

随机推荐

  1. 6、java5线程池之固定大小线程池newFixedThreadPool

    JDK文档说明: 创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程.在任意点,在大多数 nThreads 线程会处于处理任务的活动状态.如果在所有线程处于活动状态时提交附加任务,则 ...

  2. python之模块calendar(汇集了日历相关的操作)

    # -*- coding: utf-8 -*- #python 27 #xiaodeng #calendar日历模块 import calendar #3个大类: calendar.Calendar( ...

  3. windows 10 更新失败及应用商店重装问题解决记录

    简单的记录一下这次遇到的问题及解决办法. 使用的windows 10 企业版一直不能更新成功,各种办法都试过了,都是失败然后回退. 这次直接下载了1709的映像进行升级安装的,因为我的是双系统,升级安 ...

  4. appium界面运行过程(结合日志截图分析)

    appium界面运行过程: 1.启动一个http服务器:127.0.0.1:47232.根据测试代码setUp()进行初始化,在http服务器上建立一个session对象3.开始调用adb,找到连接上 ...

  5. java正则表达式去除html中所有的标签和特殊HTML字符(以&开头的)

    来源于:https://www.androiddev.net/java%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8E%BB%E9%99%A4ht ...

  6. Oracle的悲观锁和乐观锁

    为了得到最大的性能,一般数据库都有并发机制,不过带来的问题就是数据访问的冲突.为了解决这个问题,大多数数据库用的方法就是数据的锁定. 数据的锁定分为两种方法,第一种叫做悲观锁,第二种叫做乐观锁.什么叫 ...

  7. 【RS】CoupledCF: Learning Explicit and Implicit User-item Couplings in Recommendation for Deep Collaborative Filtering-CoupledCF:在推荐系统深度协作过滤中学习显式和隐式的用户物品耦合

    [论文标题]CoupledCF: Learning Explicit and Implicit User-item Couplings in Recommendation for Deep Colla ...

  8. 【MATLAB】matlabR2010a与vs2010联合编译设置

    在matlab中编译C++程序,首先要配置编译器>> mex -setupPlease choose your compiler for building external interfa ...

  9. HDU 3951 Coin Game (简单博弈)

    Coin Game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  10. Tensorflow CNN入门

    一.概论 以图像识别来举例,比如我们让计算机如何识别一张猫的图片识别出猫呢? 老式的计算机视觉是如何做的呢? 比如OpenCV: 首先理解很多算法,比如如何检测线条(Edge Detection) 如 ...