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)上继续维护, 相对于旧版本:
    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;            }        }    }
  • 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()的同时异步执行线程,清除请求结果和关闭链接。这个过程对调用者来说是异步的无感知的。

总结

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