XUtils下载地址 http://www.oschina.net/p/xutils
官方介绍:
常见问题:
以下是对demo的分析
进入HttpFragment
/**
* 自定义实体参数类请参考:
* 请求注解 {@link org.xutils.http.annotation.HttpRequest}
* 请求注解处理模板接口 {@link org.xutils.http.app.ParamsBuilder}
*
* 需要自定义类型作为callback的泛型时, 参考:
* 响应注解 {@link org.xutils.http.annotation.HttpResponse}
* 响应注解处理模板接口 {@link org.xutils.http.app.ResponseParser}
*
* 示例: 查看 org.xutils.sample.http 包里的代码
*/
BaiduParams params = new BaiduParams();
params.wd = "xUtils";
// 有上传文件时使用multipart表单, 否则上传原始文件流.
// params.setMultipart(true);
// 上传文件方式 1
// params.uploadFile = new File("/sdcard/test.txt");
// 上传文件方式 2
// params.addBodyParameter("uploadFile", new File("/sdcard/test.txt"));
Callback.Cancelable cancelable
= x.http().get(params,
/**
* 1. callback的泛型:
* callback参数默认支持的泛型类型参见{@link org.xutils.http.loader.LoaderFactory},
* 例如: 指定泛型为File则可实现文件下载, 使用params.setSaveFilePath(path)指定文件保存的全路径.
* 默认支持断点续传(采用了文件锁和尾端校验续传文件的一致性).
* 其他常用类型可以自己在LoaderFactory中注册,
* 也可以使用{@link org.xutils.http.annotation.HttpResponse}
* 将注解HttpResponse加到自定义返回值类型上, 实现自定义ResponseParser接口来统一转换.
* 如果返回值是json形式, 那么利用第三方的json工具将十分容易定义自己的ResponseParser.
* 如示例代码{@link org.xutils.sample.http.BaiduResponse}, 可直接使用BaiduResponse作为
* callback的泛型.
*
* @HttpResponse 注解 和 ResponseParser接口仅适合做json, xml等文本类型数据的解析,
* 如果需要其他数据类型的解析可参考:
* {@link org.xutils.http.loader.LoaderFactory}
* 和 {@link org.xutils.common.Callback.PrepareCallback}.
* LoaderFactory提供PrepareCallback第一个泛型参数类型的自动转换,
* 第二个泛型参数需要在prepare方法中实现.
* (LoaderFactory中已经默认提供了部分常用类型的转换实现, 其他类型需要自己注册.)
*
* 2. callback的组合:
* 可以用基类或接口组合个种类的Callback, 见{@link org.xutils.common.Callback}.
* 例如:
* a. 组合使用CacheCallback将使请求检测缓存或将结果存入缓存(仅GET请求生效).
* b. 组合使用PrepareCallback的prepare方法将为callback提供一次后台执行耗时任务的机会,
* 然后将结果给onCache或onSuccess.
* c. 组合使用ProgressCallback将提供进度回调.
* ...(可参考{@link org.xutils.image.ImageLoader}
* 或 示例代码中的 {@link org.xutils.sample.download.DownloadCallback})
*
* 3. 请求过程拦截或记录日志: 参考 {@link org.xutils.http.app.RequestTracker}
*
* 4. 请求Header获取: 参考 {@link org.xutils.http.app.RequestInterceptListener}
*
* 5. 其他(线程池, 超时, 重定向, 重试, 代理等): 参考 {@link org.xutils.http.RequestParams}
*
**/
new Callback.CommonCallback>() {
@Override
public void onSuccess(List result) {
Toast.makeText(x.app(), result.get(0).toString(), Toast.LENGTH_LONG).show();
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
Toast.makeText(x.app(), ex.getMessage(), Toast.LENGTH_LONG).show();
if (ex instanceof HttpException) { // 网络错误
HttpException httpEx = (HttpException) ex;
int responseCode = httpEx.getCode();
String responseMsg = httpEx.getMessage();
String errorResult = httpEx.getResult();
// ...
} else { // 其他错误
// ...
}
}
@Override
public void onCancelled(CancelledException cex) {
Toast.makeText(x.app(), "cancelled", Toast.LENGTH_LONG).show();
}
@Override
public void onFinished() {
}
});
// cancelable.cancel(); // 取消请求
这块代码实现了一个简单的网络请求,一下是对代码的具体分析
注解的作用:
1、生成文档。这是最常见的,也是java 最早提供的注解。常用的有@see @param @return 等
2、跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5 开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量。以后java的程序开发,最多的也将实现注解配置,具有很大用处;
3、在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。
Java代码
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
//读取注解信息
public class ReadAnnotationInfoTest {
public static void main(String[] args) throws Exception {
// 测试AnnotationTest类,得到此类的类对象
Class c = Class.forName("com.iwtxokhtd.annotation.AnnotationTest");
// 获取该类所有声明的方法
Method[] methods = c.getDeclaredMethods();
// 声明注解集合
Annotation[] annotations;
// 遍历所有的方法得到各方法上面的注解信息
for (Method method : methods) {
// 获取每个方法上面所声明的所有注解信息
annotations = method.getDeclaredAnnotations();
// 再遍历所有的注解,打印其基本信息
System.out.println(method.getName());
for (Annotation an : annotations) {
System.out.println("方法名为:" + method.getName() + "其上面的注解为:" + an.annotationType().getSimpleName());
Method[] meths = an.annotationType().getDeclaredMethods();
// 遍历每个注解的所有变量
for (Method meth : meths) {
System.out.println("注解的变量名为:" + meth.getName());
}
}
}
}
}
/**
* Created by wyouflf on 15/7/17.
* 网络请求参数实体
*/
public class RequestParams {
// 注解及其扩展参数
private HttpRequest httpRequest;
private final String uri;
private final String[] signs;
private final String[] cacheKeys;
private ParamsBuilder builder;
private String buildUri;
private String buildCacheKey;
private SSLSocketFactory sslSocketFactory;
// 请求体内容
private HttpMethod method;
private String bodyContent;
private RequestBody requestBody;
private final List headers = new ArrayList();
private final List queryStringParams = new ArrayList();
private final List bodyParams = new ArrayList();
private final List fileParams = new ArrayList();
// 扩展参数
private Proxy proxy; // 代理
private String charset = "UTF-8";
private boolean useCookie = true; // 是否在请求过程中启用cookie
private String cacheDirName; // 缓存文件夹名称
private long cacheSize; // 缓存文件夹大小
private long cacheMaxAge; // 默认缓存存活时间, 单位:毫秒.(如果服务没有返回有效的max-age或Expires)
private boolean asJsonContent = false; // 用json形式的bodyParams上传
private Executor executor; // 自定义线程池
private Priority priority = Priority.DEFAULT; // 请求优先级
private int connectTimeout = 1000 * 15; // 连接超时时间
private boolean autoResume = true; // 是否在下载是自动断点续传
private boolean autoRename = false; // 是否根据头信息自动命名文件
private int maxRetryCount = 2; // 最大请求错误重试次数
private String saveFilePath; // 下载文件时文件保存的路径和文件名
private boolean multipart = false; // 是否强制使用multipart表单
private boolean cancelFast = false; // 是否可以被立即停止, true: 为请求创建新的线程, 取消时请求线程被立即中断.
private int loadingUpdateMaxTimeSpan = 300; // 进度刷新最大间隔时间(ms)
private HttpRetryHandler httpRetryHandler; // 自定义HttpRetryHandler
private RedirectHandler redirectHandler; // 自定义重定向接口, 默认系统自动重定向.
private RequestTracker requestTracker; // 自定义日志记录接口.
@HttpResponse(parser = JsonResponseParser.class)
public class BaiduResponse {
系统提供了解析器的结构并未提供实现
/**
* Created by wyouflf on 15/8/4.
* {@link org.xutils.http.annotation.HttpResponse} 注解的返回值转换模板
*/
public interface ResponseParser {
/**
* 检查请求相应头等处理
*
* @param request
* @throws Throwable
*/
void checkResponse(UriRequest request) throws Throwable;
/**
* 转换result为resultType类型的对象
*
* @param resultType 返回值类型(可能带有泛型信息)
* @param resultClass 返回值类型
* @param result 字符串数据
* @return
* @throws Throwable
*/
Object parse(Type resultType, Class> resultClass, String result) throws Throwable;
}
由 JsonResponseParser implements ResponseParser可以看出自定义解析器还是很方便的
/**
* Created by wyouflf on 15/11/5.
*/
public class JsonResponseParser implements ResponseParser {
@Override
public void checkResponse(UriRequest request) throws Throwable {
// custom check ?
// check header ?
}
/**
* 转换result为resultType类型的对象
*
* @param resultType 返回值类型(可能带有泛型信息)
* @param resultClass 返回值类型
* @param result 字符串数据
* @return
* @throws Throwable
*/
@Override
public Object parse(Type resultType, Class> resultClass, String result) throws Throwable {
// TODO: json to java bean
if (resultClass == List.class) {
// 这里只是个示例, 不做json转换.
List list = new ArrayList();
BaiduResponse baiduResponse = new BaiduResponse();
baiduResponse.setTest(result);
list.add(baiduResponse);
return list;
// fastJson:
// return JSON.parseArray(result,
// (Class>) ParameterizedTypeUtil.getParameterizedType(resultType, List.class, 0));
} else {
// 这里只是个示例, 不做json转换.
BaiduResponse baiduResponse = new BaiduResponse();
baiduResponse.setTest(result);
return baiduResponse;
// fastjson:
// return JSON.parseObject(result, resultClass);
}
}
}
然后进入网络请求和返回值代码块
Callback.Cancelable cancelable
= x.http().get(params,
new Callback.CommonCallback>() {
@Override
public void onSuccess(List result) {
Toast.makeText(x.app(), result.get(0).toString(), Toast.LENGTH_LONG).show();
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
Toast.makeText(x.app(), ex.getMessage(), Toast.LENGTH_LONG).show();
if (ex instanceof HttpException) { // 网络错误
HttpException httpEx = (HttpException) ex;
int responseCode = httpEx.getCode();
String responseMsg = httpEx.getMessage();
String errorResult = httpEx.getResult();
// ...
} else { // 其他错误
// ...
}
}
@Override
public void onCancelled(CancelledException cex) {
Toast.makeText(x.app(), "cancelled", Toast.LENGTH_LONG).show();
}
@Override
public void onFinished() {
}
});
public static HttpManager http() {
if (Ext.httpManager == null) {
HttpManagerImpl.registerInstance();
}
return Ext.httpManager;
}
此处创建http管理器单例
最终调用
@Override
public Callback.Cancelable request(HttpMethod method, RequestParams entity, Callback.CommonCallback callback) {
entity.setMethod(method);
Callback.Cancelable cancelable = null;
if (callback instanceof Callback.Cancelable) {
cancelable = (Callback.Cancelable) callback;
}
HttpTask task = new HttpTask(entity, cancelable, callback);
return x.task().start(task);
}
@Override
public T requestSync(HttpMethod method, RequestParams entity, Callback.TypedCallback callback) throws Throwable {
entity.setMethod(method);
HttpTask task = new HttpTask(entity, null, callback);
return x.task().startSync(task);
}
注意异步调用的返回值都是Callback.Cancelable 接口,是为了取消异步操作
Callback接口针对不同的请求定义了不同的处理方式,具体信息查看接口源码,注意此处的ResultType为泛型
不管是同步还是异步真正发起网络请求的是
HttpTask task = new HttpTask(entity, cancelable, callback);
return x.task().start(task);
/**
* Created by wyouflf on 15/7/23.
* http 请求任务
*/
public class HttpTask extends AbsTask implements ProgressHandler {
// 请求相关
private RequestParams params;
private UriRequest request;
private RequestWorker requestWorker;
private final Executor executor;
private final Callback.CommonCallback callback;
// 缓存控制
private Object rawResult = null;
private final Object cacheLock = new Object();
private volatile Boolean trustCache = null;
// 扩展callback
private Callback.CacheCallback cacheCallback;
private Callback.PrepareCallback prepareCallback;
private Callback.ProgressCallback progressCallback;
private RequestInterceptListener requestInterceptListener;
// 日志追踪
private RequestTracker tracker;
// 文件下载线程数限制
private Type loadType;
private final static int MAX_FILE_LOAD_WORKER = 3;
private final static AtomicInteger sCurrFileLoadCount = new AtomicInteger(0);
// 文件下载任务
private static final HashMap>>
DOWNLOAD_TASK = new HashMap>>(1);
private static final PriorityExecutor HTTP_EXECUTOR = new PriorityExecutor(5, true);
private static final PriorityExecutor CACHE_EXECUTOR = new PriorityExecutor(5, true);
此处对网络请求进行总体封装,包括网络请求参数、请求的发送和接收、请求发送和加载数据线程等
httpTask由TaskControllerImpl进行管理
/**
* Created by wyouflf on 15/6/5.
* 异步任务的管理类
*/
public final class TaskControllerImpl implements TaskController {
private TaskControllerImpl() {
}
private static TaskController instance;
public static void registerInstance() {
if (instance == null) {
synchronized (TaskController.class) {
if (instance == null) {
instance = new TaskControllerImpl();
}
}
}
x.Ext.setTaskController(instance);
}
调用x.task().start(task)时进入
/**
* run task
*
* @param task
* @param
* @return
*/
@Override
public AbsTask start(AbsTask task) {
TaskProxy proxy = null;
if (task instanceof TaskProxy) {
proxy = (TaskProxy) task;
} else {
proxy = new TaskProxy(task);
}
try {
proxy.doBackground();
} catch (Throwable ex) {
LogUtil.e(ex.getMessage(), ex);
}
return proxy;
}
/**
* 异步任务的代理类(仅在task包内可用)
*
* @param
*/
/*package*/ class TaskProxy extends AbsTask {
/*package*/ static final InternalHandler sHandler = new InternalHandler();
/*package*/ static final PriorityExecutor sDefaultExecutor = new PriorityExecutor(true);
private final AbsTask task;
private final Executor executor;
private volatile boolean callOnCanceled = false;
private volatile boolean callOnFinished = false;
回到TaskControllerImpl的start方法中看到proxy.doBackground()为正式调用网络请求控制,进入该方法
@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;
}
在任务线程
在构造函数中可以看出
/*package*/ TaskProxy(AbsTask 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;
}
executor若为null,那么使用系统自带的PriorityExecutor
进入PriorityExecutor可以看出这是一个使用优先级的线程池管理类
/**
* @param poolSize 工作线程数
* @param fifo 优先级相同时, 等待队列的是否优先执行先加入的任务.
*/
public PriorityExecutor(int poolSize, boolean fifo) {
BlockingQueue mPoolWorkQueue =
new PriorityBlockingQueue(MAXIMUM_POOL_SIZE, fifo ? FIFO_CMP : FILO_CMP);
mThreadPoolExecutor = new ThreadPoolExecutor(
poolSize,
MAXIMUM_POOL_SIZE,
KEEP_ALIVE,
TimeUnit.SECONDS,
mPoolWorkQueue,
sThreadFactory);
}
此处根据优先级进行了队列的排序方式
回到taskProxy doBackground方法
如果请求已经开启并在中途取消异步操作那么抛出异常终止网络请求
如果出现异常或者请求完成那么调用handler
@Override
protected void onSuccess(ResultType result) {
this.setState(State.SUCCESS);
sHandler.obtainMessage(MSG_WHAT_ON_SUCCESS, this).sendToTarget();
}
handler接收到后通知httptask
switch (msg.what) {
case MSG_WHAT_ON_WAITING: {
taskProxy.task.onWaiting();
break;
}
case MSG_WHAT_ON_START: {
taskProxy.task.onStarted();
break;
}
case MSG_WHAT_ON_SUCCESS: {
taskProxy.task.onSuccess(taskProxy.getResult());
break;
}
case MSG_WHAT_ON_ERROR: {
assert args != null;
Throwable throwable = (Throwable) args[0];
LogUtil.d(throwable.getMessage(), throwable);
taskProxy.task.onError(throwable, false);
break;
}
case MSG_WHAT_ON_UPDATE: {
taskProxy.task.onUpdate(msg.arg1, args);
break;
}
case MSG_WHAT_ON_CANCEL: {
if (taskProxy.callOnCanceled) return;
taskProxy.callOnCanceled = true;
assert args != null;
taskProxy.task.onCancelled((org.xutils.common.Callback.CancelledException) args[0]);
break;
}
case MSG_WHAT_ON_FINISHED: {
if (taskProxy.callOnFinished) return;
taskProxy.callOnFinished = true;
taskProxy.task.onFinished();
break;
}
default: {
break;
}
@Override
protected void onSuccess(ResultType result) {
if (tracker != null) {
tracker.onSuccess(request, result);
}
if (result != null) {
callback.onSuccess(result);
}
}
由taskProxy的doBackground()中可以看出网络请求的完成是由 task.setResult(task.doBackground())代码完成的,进入httptask的doBackground方法
在这个方法中才对注解、请求参数、请求线程、缓存等进行操作管理
一下是对该放方法的具体分析
首先进入
// 解析loadType
private void resolveLoadType() {
Class> callBackType = callback.getClass();
if (callback instanceof Callback.TypedCallback) {
loadType = ((Callback.TypedCallback) callback).getLoadType();
} else if (callback instanceof Callback.PrepareCallback) {
loadType = ParameterizedTypeUtil.getParameterizedType(callBackType, Callback.PrepareCallback.class, 0);
} else {
loadType = ParameterizedTypeUtil.getParameterizedType(callBackType, Callback.CommonCallback.class, 0);
}
}
Callback接口针对不同的请求定义了不同的处理方式
然后调用
// 初始化请求参数
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;
}
// invoke via HttpTask#createNewRequest
/*package*/ void init() throws Throwable {
if (!TextUtils.isEmpty(buildUri)) return;
if (TextUtils.isEmpty(uri) && getHttpRequest() == null) {
throw new IllegalStateException("uri is empty && @HttpRequest == null");
}
// init params from entity
initEntityParams();
// build uri & cacheKey
buildUri = uri;
HttpRequest httpRequest = this.getHttpRequest();
if (httpRequest != null) {
builder = httpRequest.builder().newInstance();
buildUri = builder.buildUri(httpRequest);
builder.buildParams(this);
builder.buildSign(this, httpRequest.signs());
if (sslSocketFactory == null) {
sslSocketFactory = builder.getSSLSocketFactory();
}
} else if (this.builder != null) {
builder.buildParams(this);
builder.buildSign(this, signs);
if (sslSocketFactory == null) {
sslSocketFactory = builder.getSSLSocketFactory();
}
}
}
UriRequest请求发送和数据接收是由 Uri请求创建工厂UriRequestFactory根据Callback类型和请求参数产生的
public static UriRequest getUriRequest(RequestParams params, Type loadType) throws Throwable {
String uri = params.getUri();
if (uri.startsWith("http")) {
return new HttpRequest(params, loadType);
} else if (uri.startsWith("assets://")) {
if (assetsRequestCls != null) {
Constructor extends AssetsRequest> constructor
= assetsRequestCls.getConstructor(RequestParams.class, Class.class);
return constructor.newInstance(params, loadType);
} else {
return new AssetsRequest(params, loadType);
}
} else if (uri.startsWith("file:") || uri.startsWith("/")) {
return new LocalFileRequest(params, loadType);
} else {
throw new IllegalArgumentException("The url not be support: " + uri);
}
}
public final class LoaderFactory {
private LoaderFactory() {
}
/**
* key: loadType
*/
private static final HashMap converterHashMap = new HashMap();
static {
converterHashMap.put(JSONObject.class, new JSONObjectLoader());
converterHashMap.put(JSONArray.class, new JSONArrayLoader());
converterHashMap.put(String.class, new StringLoader());
converterHashMap.put(File.class, new FileLoader());
converterHashMap.put(byte[].class, new ByteArrayLoader());
BooleanLoader booleanLoader = new BooleanLoader();
converterHashMap.put(boolean.class, booleanLoader);
converterHashMap.put(Boolean.class, booleanLoader);
IntegerLoader integerLoader = new IntegerLoader();
converterHashMap.put(int.class, integerLoader);
converterHashMap.put(Integer.class, integerLoader);
}
@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;
}
public static void registerLoader(Type type, Loader loader) {
converterHashMap.put(type, loader);
}
}
进入抽象loader类
**
* Author: wyouflf
* Time: 2014/05/26
*/
public abstract class Loader {
protected RequestParams params;
protected ProgressHandler progressHandler;
public void setParams(final RequestParams params) {
this.params = params;
}
public void setProgressHandler(final ProgressHandler callbackHandler) {
this.progressHandler = callbackHandler;
}
protected void saveStringCache(UriRequest request, String resultStr) {
if (!TextUtils.isEmpty(resultStr)) {
DiskCacheEntity entity = new DiskCacheEntity();
entity.setKey(request.getCacheKey());
entity.setLastAccess(System.currentTimeMillis());
entity.setEtag(request.getETag());
entity.setExpires(request.getExpiration());
entity.setLastModify(new Date(request.getLastModified()));
entity.setTextContent(resultStr);
LruDiskCache.getDiskCache(request.getParams().getCacheDirName()).put(entity);
}
}
public abstract Loader newInstance();
public abstract T load(final InputStream in) throws Throwable;
public abstract T load(final UriRequest request) throws Throwable;
public abstract T loadFromCache(final DiskCacheEntity cacheEntity) throws Throwable;
public abstract void save2Cache(final UriRequest request);
}
类此定义了各种数据加载类型()
LoaderFactory中数据处理类型
converterHashMap.put(JSONObject.class, new JSONObjectLoader());
converterHashMap.put(JSONArray.class, new JSONArrayLoader());
converterHashMap.put(String.class, new StringLoader());
converterHashMap.put(File.class, new FileLoader());
converterHashMap.put(byte[].class, new ByteArrayLoader());
BooleanLoader booleanLoader = new BooleanLoader();
converterHashMap.put(boolean.class, booleanLoader);
converterHashMap.put(Boolean.class, booleanLoader);
IntegerLoader integerLoader = new IntegerLoader();
converterHashMap.put(int.class, integerLoader);
converterHashMap.put(Integer.class, integerLoader);
进入JsonArrayLoader
/**
* Author: wyouflf
* Time: 2014/06/16
*/
/*package*/ class JSONArrayLoader extends Loader {
private String charset = "UTF-8";
private String resultStr = null;
@Override
public Loader newInstance() {
return new JSONArrayLoader();
}
@Override
public void setParams(final RequestParams params) {
if (params != null) {
String charset = params.getCharset();
if (!TextUtils.isEmpty(charset)) {
this.charset = charset;
}
}
}
@Override
public JSONArray load(final InputStream in) throws Throwable {
resultStr = IOUtil.readStr(in, charset);
return new JSONArray(resultStr);
}
@Override
public JSONArray load(final UriRequest request) throws Throwable {
request.sendRequest();
return this.load(request.getInputStream());
}
@Override
public JSONArray loadFromCache(final DiskCacheEntity cacheEntity) throws Throwable {
if (cacheEntity != null) {
String text = cacheEntity.getTextContent();
if (!TextUtils.isEmpty(text)) {
return new JSONArray(text);
}
}
return null;
}
@Override
public void save2Cache(UriRequest request) {
saveStringCache(request, resultStr);
}
}
@Override
public JSONArray load(final UriRequest request) throws Throwable {
request.sendRequest();
return this.load(request.getInputStream());
}
此处调起了网络请求,进入网络请求详情HttpRequest的sendRequest方法(实现数据请求方式包括AssetsRequest、HttpRequest、LocalFileRequest)
/**
* invoke via Loader
*
* @throws IOException
*/
@Override
@TargetApi(Build.VERSION_CODES.KITKAT)
public void sendRequest() throws IOException {
isLoading = false;
URL url = new URL(queryUrl);
{ // init connection
Proxy proxy = params.getProxy();
if (proxy != null) {
connection = (HttpURLConnection) url.openConnection(proxy);
} else {
connection = (HttpURLConnection) url.openConnection();
}
// try to fix bug: accidental EOFException before API 19
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
connection.setRequestProperty("Connection", "close");
}
connection.setReadTimeout(params.getConnectTimeout());
connection.setConnectTimeout(params.getConnectTimeout());
connection.setInstanceFollowRedirects(params.getRedirectHandler() == null);
if (connection instanceof HttpsURLConnection) {
SSLSocketFactory sslSocketFactory = params.getSslSocketFactory();
if (sslSocketFactory != null) {
((HttpsURLConnection) connection).setSSLSocketFactory(sslSocketFactory);
}
}
}
if (params.isUseCookie()) {// add cookies
try {
Map> singleMap =
COOKIE_MANAGER.get(url.toURI(), new HashMap>(0));
List cookies = singleMap.get("Cookie");
if (cookies != null) {
connection.setRequestProperty("Cookie", TextUtils.join(";", cookies));
}
} catch (Throwable ex) {
LogUtil.e(ex.getMessage(), ex);
}
}
{// add headers
List headers = params.getHeaders();
if (headers != null) {
for (RequestParams.Header header : headers) {
String name = header.key;
String value = header.getValueStr();
if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(value)) {
if (header.setHeader) {
connection.setRequestProperty(name, value);
} else {
connection.addRequestProperty(name, value);
}
}
}
}
}
{ // write body
HttpMethod method = params.getMethod();
connection.setRequestMethod(method.toString());
if (HttpMethod.permitsRequestBody(method)) {
RequestBody body = params.getRequestBody();
if (body != null) {
if (body instanceof ProgressBody) {
((ProgressBody) body).setProgressHandler(progressHandler);
}
String contentType = body.getContentType();
if (!TextUtils.isEmpty(contentType)) {
connection.setRequestProperty("Content-Type", contentType);
}
long contentLength = body.getContentLength();
if (contentLength < 0) {
connection.setChunkedStreamingMode(256 * 1024);
} else {
if (contentLength < Integer.MAX_VALUE) {
connection.setFixedLengthStreamingMode((int) contentLength);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
connection.setFixedLengthStreamingMode(contentLength);
} else {
connection.setChunkedStreamingMode(256 * 1024);
}
}
connection.setRequestProperty("Content-Length", String.valueOf(contentLength));
connection.setDoOutput(true);
body.writeTo(connection.getOutputStream());
}
}
}
if (params.isUseCookie()) { // save cookies
try {
Map> headers = connection.getHeaderFields();
if (headers != null) {
COOKIE_MANAGER.put(url.toURI(), headers);
}
} catch (Throwable ex) {
LogUtil.e(ex.getMessage(), ex);
}
}
// check response code
responseCode = connection.getResponseCode();
if (responseCode >= 300) {
HttpException httpException = new HttpException(responseCode, this.getResponseMessage());
try {
httpException.setResult(IOUtil.readStr(this.getInputStream(), params.getCharset()));
} catch (Throwable ignored) {
}
LogUtil.e(httpException.toString() + ", url: " + queryUrl);
throw httpException;
}
isLoading = true;
}
@Override
public JSONArray load(final InputStream in) throws Throwable {
resultStr = IOUtil.readStr(in, charset);
return new JSONArray(resultStr);
}
对流进行处理
public static String readStr(InputStream in, String charset) throws IOException {
if (TextUtils.isEmpty(charset)) charset = "UTF-8";
if (!(in instanceof BufferedInputStream)) {
in = new BufferedInputStream(in);
}
Reader reader = new InputStreamReader(in, charset);
StringBuilder sb = new StringBuilder();
char[] buf = new char[1024];
int len;
while ((len = reader.read(buf)) >= 0) {
sb.append(buf, 0, len);
}
return sb.toString().trim();
}
到此网络请求处理完成
再次回到HttpTask doBackground中
创建UriRequest后
然后检测
// 文件下载冲突检测
private void checkDownloadTask() {
if (File.class == loadType) {
synchronized (DOWNLOAD_TASK) {
String downloadTaskKey = this.params.getSaveFilePath();
/*{
// 不处理缓存文件下载冲突,
// 缓存文件下载冲突会抛出FileLockedException异常,
// 使用异常处理控制是否重新尝试下载.
if (TextUtils.isEmpty(downloadTaskKey)) {
downloadTaskKey = this.request.getCacheKey();
}
}*/
if (!TextUtils.isEmpty(downloadTaskKey)) {
WeakReference> taskRef = DOWNLOAD_TASK.get(downloadTaskKey);
if (taskRef != null) {
HttpTask> task = taskRef.get();
if (task != null) {
task.cancel();
task.closeRequestSync();
}
DOWNLOAD_TASK.remove(downloadTaskKey);
}
DOWNLOAD_TASK.put(downloadTaskKey, new WeakReference>(this));
} // end if (!TextUtils.isEmpty(downloadTaskKey))
}
}
}
如果当前请求下载的是文件并且正在执行那么停止该任务再次重新放入下载列表
然后设置请求的重连次数最大为3
然后从缓存中取如果缓存有值直接返回数据,然后没有那么将会建立请求发送和加载数据线程RequestWorker,此线程调用Loader.load()发起网络请求,并拿到返回值,如果callback实现了Callback.CacheCallback
关于http缓存的存取还是比较容易理解的,请自己查看
到此Xutils的http模块异步请求基本分析完毕,不懂的地方请自己查看源码