源码分析--xutil3 网络源码分析

这边查找的是同步请求的post方法(异步请求的方法也类似,最终同步异步都是会调用到同一块代码),流程如下

public <T> T postSync(RequestParams entity, Class<T> resultType) throws Throwable {
    return this.requestSync(HttpMethod.POST, entity, resultType);
}
public <T> T requestSync(HttpMethod method, RequestParams entity, Class<T> resultType) throws Throwable {
    HttpManagerImpl.DefaultSyncCallback<T> callback = new HttpManagerImpl.DefaultSyncCallback(resultType);
    return this.requestSync(method, entity, (TypedCallback)callback);
}

public <T> T requestSync(HttpMethod method, RequestParams entity, TypedCallback<T> callback) throws Throwable {
    entity.setMethod(method);
    HttpTask<T> task = new HttpTask(entity, (Cancelable)null, callback);
    return x.task().startSync(task);
}

最后封装了一个task去执行网络请求任务,值得注意的是在虽然xutil3里面包括了很多功能,但是大部分的功能都会用到他自身的task的模式,所以想要了解xutil的源码,建议先看一下他自己的task(任务)相关功能的源码。

//TaskControllerImpl
public <T> T startSync(AbsTask<T> task) throws Throwable {
    Object result = null;

    try {
        task.onWaiting();
        task.onStarted();
        result = task.doBackground();
        task.onSuccess(result);
    } catch (CancelledException var8) {
        task.onCancelled(var8);
    } catch (Throwable var9) {
        task.onError(var9, false);
        throw var9;
    } finally {
        task.onFinished();
    }

    return result;
}

主要看doBackground方法,对应的是前一步创建的HttpTask,看一下源码

//HttpTask
protected ResultType doBackground() throws Throwable {
    if (this.isCancelled()) {
        throw new CancelledException("cancelled before request");
    } else {
        ResultType result = null;
        this.resolveLoadType();
        this.request = this.createNewRequest();
        this.checkDownloadTask();
        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());
        if (this.isCancelled()) {
            throw new CancelledException("cancelled before request");
        } else {
            Object cacheResult = null;
            if (this.cacheCallback != null && HttpMethod.permitsCache(this.params.getMethod())) {
                try {
                    this.clearRawResult();
                    LogUtil.d("load cache: " + this.request.getRequestUri());
                    this.rawResult = this.request.loadResultFromCache();
                } catch (Throwable var35) {
                    LogUtil.w("load disk cache error", var35);
                }

                if (this.isCancelled()) {
                    this.clearRawResult();
                    throw new CancelledException("cancelled before request");
                }

                if (this.rawResult != null) {
                    if (this.prepareCallback != null) {
                        try {
                            cacheResult = this.prepareCallback.prepare(this.rawResult);
                        } catch (Throwable var33) {
                            cacheResult = null;
                            LogUtil.w("prepare disk cache error", var33);
                        } finally {
                            this.clearRawResult();
                        }
                    } else {
                        cacheResult = this.rawResult;
                    }

                    if (this.isCancelled()) {
                        throw new CancelledException("cancelled before request");
                    }

                    if (cacheResult != null) {
                        this.update(2, new Object[]{cacheResult});

                        while(this.trustCache == null) {
                            Object var7 = this.cacheLock;
                            synchronized(this.cacheLock) {
                                try {
                                    this.cacheLock.wait();
                                } catch (InterruptedException var30) {
                                    throw new CancelledException("cancelled before request");
                                } catch (Throwable var31) {
                                    ;
                                }
                            }
                        }

                        if (this.trustCache) {
                            return null;
                        }
                    }
                }
            }

            if (this.trustCache == null) {
                this.trustCache = false;
            }

            if (cacheResult == null) {
                this.request.clearCacheHeader();
            }

            if (this.callback instanceof ProxyCacheCallback && ((ProxyCacheCallback)this.callback).onlyCache()) {
                return null;
            } else {
                retry = true;

                while(retry) {
                    retry = false;

                    try {
                        if (this.isCancelled()) {
                            throw new CancelledException("cancelled before request");
                        }

                        this.request.close();

                        try {
                            this.clearRawResult();
                            LogUtil.d("load: " + this.request.getRequestUri());
                            this.requestWorker = new HttpTask.RequestWorker((HttpTask.RequestWorker)null);
                            this.requestWorker.request();
                            if (this.requestWorker.ex != null) {
                                throw this.requestWorker.ex;
                            }

                            this.rawResult = this.requestWorker.result;
                        } catch (Throwable var36) {
                            this.clearRawResult();
                            if (this.isCancelled()) {
                                throw new CancelledException("cancelled during request");
                            }

                            throw var36;
                        }

                        if (this.prepareCallback != null) {
                            if (this.isCancelled()) {
                                throw new CancelledException("cancelled before request");
                            }

                            try {
                                result = this.prepareCallback.prepare(this.rawResult);
                            } finally {
                                this.clearRawResult();
                            }
                        } else {
                            result = this.rawResult;
                        }

                        if (this.cacheCallback != null && HttpMethod.permitsCache(this.params.getMethod())) {
                            this.request.save2Cache();
                        }

                        if (this.isCancelled()) {
                            throw new CancelledException("cancelled after request");
                        }
                    } catch (HttpRedirectException var37) {
                        retry = true;
                        LogUtil.w("Http Redirect:" + this.params.getUri());
                    } catch (Throwable var38) {
                        switch(this.request.getResponseCode()) {
                        case 204:
                        case 205:
                        case 304:
                            return null;
                        default:
                            exception = var38;
                            if (this.isCancelled() && !(var38 instanceof CancelledException)) {
                                exception = new CancelledException("canceled by user");
                            }

                            ++retryCount;
                            retry = retryHandler.canRetry(this.request, (Throwable)exception, retryCount);
                        }
                    }
                }

                if (exception != null && result == null && !this.trustCache) {
                    this.hasException = true;
                    throw (Throwable)exception;
                } else {
                    return result;
                }
            }
        }
    }
}

代码很长,我们分步骤看。首先,初始话数据,然后检查缓存,如果有缓存且缓存可用,则把赋值成员变量rawResult ,并不执行后续的网络操作。如果不用缓存,折执行下面的代码


    retry = true;

    while(retry) {
        retry = false;

        try {
            if (this.isCancelled()) {
                throw new CancelledException("cancelled before request");
            }

            this.request.close();

            try {
                this.clearRawResult();
                LogUtil.d("load: " + this.request.getRequestUri());
                this.requestWorker = new HttpTask.RequestWorker((HttpTask.RequestWorker)null);
                this.requestWorker.request();
                if (this.requestWorker.ex != null) {
                    throw this.requestWorker.ex;
                }

                this.rawResult = this.requestWorker.result;
            } catch (Throwable var36) {
                this.clearRawResult();
                if (this.isCancelled()) {
                    throw new CancelledException("cancelled during request");
                }

                throw var36;
            }

            if (this.prepareCallback != null) {
                if (this.isCancelled()) {
                    throw new CancelledException("cancelled before request");
                }

                try {
                    result = this.prepareCallback.prepare(this.rawResult);
                } finally {
                    this.clearRawResult();
                }
            } else {
                result = this.rawResult;
            }

            if (this.cacheCallback != null && HttpMethod.permitsCache(this.params.getMethod())) {
                this.request.save2Cache();
            }

            if (this.isCancelled()) {
                throw new CancelledException("cancelled after request");
            }
        } catch (HttpRedirectException var37) {
            retry = true;
            LogUtil.w("Http Redirect:" + this.params.getUri());
        } catch (Throwable var38) {
            switch(this.request.getResponseCode()) {
            case 204:
            case 205:
            case 304:
                return null;
            default:
                exception = var38;
                if (this.isCancelled() && !(var38 instanceof CancelledException)) {
                    exception = new CancelledException("canceled by user");
                }

                ++retryCount;
                retry = retryHandler.canRetry(this.request, (Throwable)exception, retryCount);
            }
        }
    }

    if (exception != null && result == null && !this.trustCache) {
        this.hasException = true;
        throw (Throwable)exception;
    } else {
        return result;
    }

可以看到里面有网络请求 和 重试的逻辑,主要看一下网络请求的逻辑。关键代码是这几行

this.requestWorker = new HttpTask.RequestWorker((HttpTask.RequestWorker)null);
this.requestWorker.request();
if (this.requestWorker.ex != null) {
    throw this.requestWorker.ex;
}

this.rawResult = this.requestWorker.result;

可以看到创建了一个RequestWork内部类然后执行了request()方法,跟进看一下

public void request() {
    try {
        boolean interrupted = false;
        if (File.class == HttpTask.this.loadType) {
            while(true) {
                if (HttpTask.sCurrFileLoadCount.get() >= 3 && !HttpTask.this.isCancelled()) {
                    synchronized(HttpTask.sCurrFileLoadCount) {
                        try {
                            HttpTask.sCurrFileLoadCount.wait(10L);
                            continue;
                        } catch (InterruptedException var21) {
                            interrupted = true;
                        } catch (Throwable var22) {
                            continue;
                        }
                    }
                }

                HttpTask.sCurrFileLoadCount.incrementAndGet();
                break;
            }
        }

        if (interrupted || HttpTask.this.isCancelled()) {
            throw new CancelledException("cancelled before request" + (interrupted ? "(interrupted)" : ""));
        }

        try {
            HttpTask.this.request.setRequestInterceptListener(HttpTask.this.requestInterceptListener);
            this.result = HttpTask.this.request.loadResult();
        } catch (Throwable var20) {
            this.ex = var20;
        }

        if (this.ex != null) {
            throw this.ex;
        }
    } catch (Throwable var24) {
        this.ex = var24;
        if (var24 instanceof HttpException) {
            HttpException httpEx = (HttpException)var24;
            int errorCode = httpEx.getCode();
            if (errorCode == 301 || errorCode == 302) {
                RedirectHandler redirectHandler = HttpTask.this.params.getRedirectHandler();
                if (redirectHandler != null) {
                    try {
                        RequestParams redirectParams = redirectHandler.getRedirectParams(HttpTask.this.request);
                        if (redirectParams != null) {
                            if (redirectParams.getMethod() == null) {
                                redirectParams.setMethod(HttpTask.this.params.getMethod());
                            }

                            HttpTask.this.params = redirectParams;
                            HttpTask.this.request = HttpTask.this.createNewRequest();
                            this.ex = new HttpRedirectException(errorCode, httpEx.getMessage(), httpEx.getResult());
                        }
                    } catch (Throwable var19) {
                        this.ex = var24;
                    }
                }
            }
        }
    } finally {
        if (File.class == HttpTask.this.loadType) {
            synchronized(HttpTask.sCurrFileLoadCount) {
                HttpTask.sCurrFileLoadCount.decrementAndGet();
                HttpTask.sCurrFileLoadCount.notifyAll();
            }
        }

    }

}

核心代码是

this.result = HttpTask.this.request.loadResult();

这个request是在doBackGround里面创建的

protected ResultType doBackground() throws Throwable {
    if (this.isCancelled()) {
        throw new CancelledException("cancelled before request");
    } else {
        ResultType result = null;
        this.resolveLoadType();
        this.request = this.createNewRequest();
        ...
}

继续跟踪

//HttpTask
private UriRequest createNewRequest() throws Throwable {
    this.params.init();
    UriRequest result = UriRequestFactory.getUriRequest(this.params, this.loadType);
    result.setCallingClassLoader(this.callback.getClass().getClassLoader());
    result.setProgressHandler(this);
    this.loadingUpdateMaxTimeSpan = (long)this.params.getLoadingUpdateMaxTimeSpan();
    this.update(1, new Object[]{result});
    return result;
}

//UriRequestFactory
public static UriRequest getUriRequest(RequestParams params, Type loadType) throws Throwable {
    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";
    }

    if (!TextUtils.isEmpty(scheme)) {
        Class<? extends UriRequest> cls = (Class)SCHEME_CLS_MAP.get(scheme);
        if (cls != null) {
            Constructor<? extends UriRequest> constructor = cls.getConstructor(RequestParams.class, Class.class);
            return (UriRequest)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);
    }
}

由于参数是以“http”开头,所以这里返回的是HttpRequest类,看一下里面的loadResult方法

//HttpRequest
public Object loadResult() throws Throwable {
    this.isLoading = true;
    return super.loadResult();
}
//HttpRequest的父类UriRequest
public Object loadResult() throws Throwable {
    return this.loader.load(this);
}

那么现在问题就是找到这个loader了,这个loader是在URIRequest的构造器中被初始话

//UriRequest
UriRequest(RequestParams params, Type loadType) throws Throwable {
    this.params = params;
    this.queryUrl = this.buildQueryUrl(params);
    this.loader = LoaderFactory.getLoader(loadType, params);
}

//LoaderFactory
public static Loader<?> getLoader(Type type, RequestParams params) {
    Loader<?> result = (Loader)converterHashMap.get(type);
    Object result;
    if (result == null) {
        result = new ObjectLoader(type);
    } else {
        result = result.newInstance();
    }

    ((Loader)result).setParams(params);
    return (Loader)result;
}

可以看到是创建的是ObjectLoader类,看一下这个类的load方法


public Object load(InputStream in) throws Throwable {
    Object result;
    if (this.parser instanceof InputStreamResponseParser) {
        result = ((InputStreamResponseParser)this.parser).parse(this.objectType, this.objectClass, in);
    } else {
        this.resultStr = IOUtil.readStr(in, this.charset);
        result = this.parser.parse(this.objectType, this.objectClass, this.resultStr);
    }

    return result;
}

public Object load(UriRequest request) throws Throwable {
    try {
        request.sendRequest();
    } finally {
        this.parser.checkResponse(request);
    }

    return this.load(request.getInputStream());
}

由于传入的参数是URIRequest,所以这里用的是下面的load方法,我们回去看一下HttPRequest的sendRequest方法。

//HttpRequest
@TargetApi(19)
public void sendRequest() throws Throwable {
    this.isLoading = false;
    this.responseCode = 0;
    URL url = new URL(this.queryUrl);
    Proxy proxy = this.params.getProxy();
    if (proxy != null) {
        this.connection = (HttpURLConnection)url.openConnection(proxy);
    } else {
        this.connection = (HttpURLConnection)url.openConnection();
    }

    if (VERSION.SDK_INT < 19) {
        this.connection.setRequestProperty("Connection", "close");
    }

    this.connection.setReadTimeout(this.params.getConnectTimeout());
    this.connection.setConnectTimeout(this.params.getConnectTimeout());
    this.connection.setInstanceFollowRedirects(this.params.getRedirectHandler() == null);
    if (this.connection instanceof HttpsURLConnection) {
        SSLSocketFactory sslSocketFactory = this.params.getSslSocketFactory();
        if (sslSocketFactory != null) {
            ((HttpsURLConnection)this.connection).setSSLSocketFactory(sslSocketFactory);
        }
    }

    Map headers;
    if (this.params.isUseCookie()) {
        try {
            headers = COOKIE_MANAGER.get(url.toURI(), new HashMap(0));
            List<String> cookies = (List)headers.get("Cookie");
            if (cookies != null) {
                this.connection.setRequestProperty("Cookie", TextUtils.join(";", cookies));
            }
        } catch (Throwable var11) {
            LogUtil.e(var11.getMessage(), var11);
        }
    }

    List<Header> headers = this.params.getHeaders();
    if (headers != null) {
        Iterator var4 = headers.iterator();

        while(var4.hasNext()) {
            Header header = (Header)var4.next();
            String name = header.key;
            String value = header.getValueStr();
            if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(value)) {
                if (header.setHeader) {
                    this.connection.setRequestProperty(name, value);
                } else {
                    this.connection.addRequestProperty(name, value);
                }
            }
        }
    }

    if (this.requestInterceptListener != null) {
        this.requestInterceptListener.beforeRequest(this);
    }

    HttpMethod method = this.params.getMethod();

    try {
        this.connection.setRequestMethod(method.toString());
    } catch (ProtocolException var10) {
        try {
            Field methodField = HttpURLConnection.class.getDeclaredField("method");
            methodField.setAccessible(true);
            methodField.set(this.connection, method.toString());
        } catch (Throwable var9) {
            throw var10;
        }
    }

    if (HttpMethod.permitsRequestBody(method)) {
        RequestBody body = this.params.getRequestBody();
        if (body != null) {
            if (body instanceof ProgressBody) {
                ((ProgressBody)body).setProgressHandler(this.progressHandler);
            }

            String contentType = body.getContentType();
            if (!TextUtils.isEmpty(contentType)) {
                this.connection.setRequestProperty("Content-Type", contentType);
            }

            long contentLength = body.getContentLength();
            if (contentLength < 0L) {
                this.connection.setChunkedStreamingMode(262144);
            } else if (contentLength < 2147483647L) {
                this.connection.setFixedLengthStreamingMode((int)contentLength);
            } else if (VERSION.SDK_INT >= 19) {
                this.connection.setFixedLengthStreamingMode(contentLength);
            } else {
                this.connection.setChunkedStreamingMode(262144);
            }

            this.connection.setRequestProperty("Content-Length", String.valueOf(contentLength));
            this.connection.setDoOutput(true);
            body.writeTo(this.connection.getOutputStream());
        }
    }

    if (this.params.isUseCookie()) {
        try {
            headers = this.connection.getHeaderFields();
            if (headers != null) {
                COOKIE_MANAGER.put(url.toURI(), headers);
            }
        } catch (Throwable var8) {
            LogUtil.e(var8.getMessage(), var8);
        }
    }

    this.responseCode = this.connection.getResponseCode();
    if (this.requestInterceptListener != null) {
        this.requestInterceptListener.afterRequest(this);
    }

    if (this.responseCode != 204 && this.responseCode != 205) {
        if (this.responseCode >= 300) {
            HttpException httpException = new HttpException(this.responseCode, this.getResponseMessage());

            try {
                httpException.setResult(IOUtil.readStr(this.getInputStream(), this.params.getCharset()));
            } catch (Throwable var7) {
                ;
            }

            LogUtil.e(httpException.toString() + ", url: " + this.queryUrl);
            throw httpException;
        } else {
            this.isLoading = true;
        }
    } else {
        throw new HttpException(this.responseCode, this.getResponseMessage());
    }
}

这里我们就可以看到了网络请求的方法了,这里用的HttpURLConnection,可以看到这里的网络请求,也支持SSL。最后在这一行里面获取了response

body.writeTo(this.connection.getOutputStream());

在下面的代码分别就是,处理cookie,然后把部分连接错误的response code以Exceptions的形式抛出,而正常结果就返回出来。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值