这边查找的是同步请求的post方法(异步请求的方法也类似,最终同步异步都是会调用到同一块代码),流程如下
public T postSync(RequestParams entity, Class resultType) throws Throwable {
return this.requestSync(HttpMethod.POST, entity, resultType);
}
public T requestSync(HttpMethod method, RequestParams entity, Class resultType) throws Throwable {
HttpManagerImpl.DefaultSyncCallback callback = new HttpManagerImpl.DefaultSyncCallback(resultType);
return this.requestSync(method, entity, (TypedCallback)callback);
}
public T requestSync(HttpMethod method, RequestParams entity, TypedCallback callback) throws Throwable {
entity.setMethod(method);
HttpTask task = new HttpTask(entity, (Cancelable)null, callback);
return x.task().startSync(task);
}
最后封装了一个task去执行网络请求任务,值得注意的是在虽然xutil3里面包括了很多功能,但是大部分的功能都会用到他自身的task的模式,所以想要了解xutil的源码,建议先看一下他自己的task(任务)相关功能的源码。
//TaskControllerImpl
public T startSync(AbsTask 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 cookies = (List)headers.get("Cookie");
if (cookies != null) {
this.connection.setRequestProperty("Cookie", TextUtils.join(";", cookies));
}
} catch (Throwable var11) {
LogUtil.e(var11.getMessage(), var11);
}
}
List 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的形式抛出,而正常结果就返回出来。