哪个热心网友易先生可以帮我创一个QQ号?创完后请告诉我帐号及密码与验证码

xutils 3.0 post 使用
时间: 09:14:49
&&&& 阅读:476
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&github:
xUtils3简介
xUtils 包含了很多实用的android工具.
xUtils 支持超大文件(超过2G)上传,更全面的http请求协议支持(11种谓词),拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响...
xUtils 最低兼容Android 4.0 (api level 14). ()
xUtils3变化较多所以建立了新的项目不在旧版(/wyouflf/xUtils)上继续维护, 相对于旧版本:
HTTP实现替换HttpClient为UrlConnection, 自动解析回调泛型, 更安全的断点续传策略.
支持标准的Cookie策略, 区分domain, path...
事件注解去除不常用的功能, 提高性能.
数据库api简化提高性能, 达到和greenDao一致的性能.
图片绑定支持gif, 支持圆角, 圆形, 方形等裁剪, 支持自动旋转
使用前配置
需要的权限
&uses-permission android:name="android.permission.INTERNET" /&
&uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&
// 在application的onCreate中初始化
public void onCreate() {
super.onCreate();
x.Ext.init(this);
x.Ext.setDebug(true); // 是否输出debug日志
* 自定义实体参数类请参考:
* 请求注解 {@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 包里的代码
RequestParams params = new RequestParams (url);
// 有上传文件时使用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().post(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的泛型.
* 2. callback的组合:
* 可以用基类或接口组合个种类的Callback, 见{@link mon.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.InterceptRequestListener}
* 5. 其他(线程池, 超时, 重定向, 重试, 代理等): 参考 {@link org.xutils.http.RequestParams
new monCallback&String&() {
public void onSuccess(String result) {
Toast.makeText(x.app(), result, Toast.LENGTH_LONG).show();
public void onError(Throwable ex, boolean isOnCallback) {
//Toast.makeText(x.app(), ex.getMessage(), Toast.LENGTH_LONG).show();
if (ex instanceof HttpException) { // 网络错误
HttpException httpEx = (HttpException)
int responseCode = httpEx.getCode();
String responseMsg = httpEx.getMessage();
String errorResult = httpEx.getResult();
} else { // 其他错误
Toast.makeText(x.app(), ex.getMessage(), Toast.LENGTH_LONG).show();
public void onCancelled(CancelledException cex) {
Toast.makeText(x.app(), "cancelled", Toast.LENGTH_LONG).show();
public void onFinished() {
// cancelable.cancel(); // 取消
// 如果需要记录请求的日志, 可使用RequestTracker接口(优先级依次降低, 找到一个实现后会忽略后面的):
// 1. 自定义Callback同时实现RequestTracker接口;
// 2. 自定义ResponseParser同时实现RequestTracker接口;
// 3. 在LoaderFactory注册.
proguard-project中加入:&
 -libraryjars libs/xUtils-3.1.14.jar&
& &-keep class com.lidroid.** { *; }&
& &-keepattributes&Signature
&标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&原文:/andlp/p/5044116.html
教程昨日排行
&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!>> xutils3 项目源码
xutils3 项目源码
所属分类:
下载地址:
xUtils3.0.rar文件大小:1.94 MB
分享有礼! 》
请点击右侧的分享按钮,把本代码分享到各社交媒体。
通过您的分享链接访问Codeforge,每来2个新的IP,您将获得0.1 积分的奖励。
通过您的分享链接,每成功注册一个用户,该用户在Codeforge上所获得的每1个积分,您都将获得0.2 积分的分成奖励。
xUtils3简介
xUtils 包含了很多实用的android工具.
xUtils 支持超大文件(超过2G)上传,更全面的http请求协议支持(11种谓词),拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响...
xUtils 最低兼容Android 4.0 (api level 14). ()
xUtils3变化较多所以建立了新的项目不在旧版(/wyouflf/xUtils)上继续维护, 相对于旧版本:
HTTP实现替换HttpClient为UrlConnection, 自动解析回调泛型, 更安全的断点续传策略.
支持标准的Cookie策略, 区分domain, path...
事件注解去除不常用的功能, 提高性能.
数据库api简化提高性能, 达到和greenDao一致的性能.
图片绑定支持gif(受系统兼容性影响, 部分gif文件只能静态显示), 支持圆角, 圆形, 方形等裁剪, 支持自动旋转...
Sponsored links
源码文件列表
温馨提示: 点击源码文件名可预览文件内容哦 ^_^
.classpath364.00 B01-12-15 08:59
.project842.00 B01-12-15 08:59
org.eclipse.jdt.core.prefs177.00 B01-12-15 08:59
1.05 kB01-12-15 09:04
1.05 kB07-12-15 15:06
BuildConfig.class345.00 B17-12-15 18:49
MainActivity$1.class1.91 kB17-12-15 19:14
MainActivity$2.class1.63 kB17-12-15 19:14
MainActivity$3.class951.00 B17-12-15 19:14
MainActivity.class4.39 kB17-12-15 19:14
MyApplication.class564.00 B17-12-15 18:49
R$attr.class340.00 B17-12-15 18:49
R$dimen.class461.00 B17-12-15 18:49
R$drawable.class407.00 B17-12-15 18:49
R$id.class536.00 B17-12-15 18:49
R$layout.class403.00 B17-12-15 18:49
R$menu.class388.00 B17-12-15 18:49
R$string.class472.00 B17-12-15 18:49
R$style.class431.00 B17-12-15 18:49
R.class673.00 B17-12-15 18:49
StudentInfo.class1.08 kB17-12-15 18:49
jarlist.cache119.00 B17-12-15 18:49
160.00 B07-12-15 15:06
2.68 kB17-12-15 18:49
ic_launcher-web.png50.19 kB01-12-15 08:59
android-support-v4.jar1.30 MB01-12-15 09:00
classes.jar242.89 kB01-12-15 09:00
libwebpbackport.so325.25 kB01-12-15 09:00
libwebpbackport.so341.26 kB01-12-15 09:00
libwebpbackport.so425.38 kB01-12-15 09:00
781.00 B01-12-15 08:59
project.properties563.00 B01-12-15 08:59
ic_launcher.png7.48 kB01-12-15 08:59
ic_launcher.png3.69 kB01-12-15 08:59
ic_launcher.png12.22 kB01-12-15 08:59
ic_launcher.png24.20 kB01-12-15 08:59
1.20 kB01-12-15 09:02
261.00 B01-12-15 08:59
218.00 B01-12-15 08:59
221.00 B01-12-15 08:59
695.00 B01-12-15 08:59
201.00 B01-12-15 08:59
275.00 B01-12-15 08:59
332.00 B01-12-15 08:59
389.00 B01-12-15 08:59
4.40 kB17-12-15 19:14
303.00 B01-12-15 09:01
627.00 B01-12-15 09:02
&xutils&0.00 B17-12-15 19:30
&longyue&0.00 B17-12-15 19:30
&xutils&0.00 B17-12-15 19:30
&xutils&0.00 B17-12-15 19:30
&com&0.00 B17-12-15 19:30
&longyue&0.00 B17-12-15 19:30
&armeabi&0.00 B17-12-15 19:30
&armeabi-v7a&0.00 B17-12-15 19:30
&x86&0.00 B17-12-15 19:30
&longyue&0.00 B17-12-15 19:30
&classes&0.00 B17-12-15 19:30
&res&0.00 B04-12-15 17:29
&com&0.00 B17-12-15 19:30
&jni&0.00 B17-12-15 19:30
&drawable-hdpi&0.00 B17-12-15 19:30
&drawable-ldpi&0.00 B01-12-15 08:59
&drawable-mdpi&0.00 B17-12-15 19:30
&drawable-xhdpi&0.00 B17-12-15 19:30
&drawable-xxhdpi&0.00 B17-12-15 19:30
&layout&0.00 B17-12-15 19:30
&menu&0.00 B17-12-15 19:30
&values&0.00 B17-12-15 19:30
&values-sw600dp&0.00 B17-12-15 19:30
&values-sw720dp-land&0.00 B17-12-15 19:30
&values-v11&0.00 B17-12-15 19:30
&values-v14&0.00 B17-12-15 19:30
&com&0.00 B17-12-15 19:30
&.settings&0.00 B17-12-15 19:30
&assets&0.00 B01-12-15 08:59
&bin&0.00 B17-12-15 19:30
&gen&0.00 B17-12-15 19:30
&libs&0.00 B17-12-15 19:30
&res&0.00 B17-12-15 19:30
&src&0.00 B17-12-15 19:30
&xUtils&0.00 B17-12-15 19:30
(提交有效评论获得积分)
评论内容不能少于15个字,不要超出160个字。
评价成功,多谢!
下载xUtils3.0.rar
CodeForge积分(原CF币)全新升级,功能更强大,使用更便捷,不仅可以用来下载海量源代码马上还可兑换精美小礼品了
您的积分不足,优惠套餐快速获取 30 积分
10积分 / ¥100
30积分 / ¥200原价 ¥300 元
100积分 / ¥500原价 ¥1000 元
订单支付完成后,积分将自动加入到您的账号。以下是优惠期的人民币价格,优惠期过后将恢复美元价格。
支付宝支付宝付款
微信钱包微信付款
更多付款方式:、
您本次下载所消耗的积分将转交上传作者。
同一源码,30天内重复下载,只扣除一次积分。
鲁ICP备号-3 runtime:Elapsed:98.715ms - init:0.1;find:0.9;t:3.8;tags:0.3;related:41.1;comment:0.2; 5.8
登录 CodeForge
还没有CodeForge账号?
Switch to the English version?
^_^"呃 ...
Sorry!这位大神很神秘,未开通博客呢,请浏览一下其他的吧商城项目实战 | 10.1 xUtils3 详细介绍以及 ViewUtils 的使用方法_Android开发-织梦者
当前位置:&>&&>& > 商城项目实战 | 10.1 xUtils3 详细介绍以及 ViewUtils 的使用方法
商城项目实战 | 10.1 xUtils3 详细介绍以及 ViewUtils 的使用方法
本文为菜鸟窝作者刘婷的连载。”商城项目实战”系列来聊聊仿”京东的购物商城”如何实现。
刚开始的时候,在 GitHub 上面出现了一款强大的开源框架叫 xUtils,里面包含了很多实用的android工具,并且支持大文件上传,更全面的 http 请求协议支持(10种谓词),拥有更加灵活的 ORM,更多的事件注解支持且不受混淆影响,该框架最低兼容版本为 android 2.2 (api level 8)。但是随着
版本的不断更新,特别是 Android 6.0 之后,xUtils 的兼容不是很好,因此就出现了升级版的 xUtils,也就是 xUtils3。
xUtils3 详细介绍
xUtils3 是 xUtils 的升级版本,包含了orm, http(s), image, view注解, 但依然很轻量级(246K), 最主要是特性强大, 方便扩展,当然对比之前的 xUtils,在 xUtils3 中很多的 API 接口都已经改变了,使用方法也和之前不同了,所以本文主要是讲解最新的 xUtils3 的详细介绍以及该框架下的 ViewUtils 模块的最新用法。
1. xUtils3 的特性
1.1 xUtils3 的主要特性
xUtils3 的主要特性如下。
1.稳定的基石: AbsTask 和统一的回调接口 Callback, 任何异常, 即使你的回调方法实现有异常都会进入 onError,任何情况下 onFinished 总会让你知道任务结束了。
2.基于高效稳定的 orm 工具,http 模块得以更方便的实现 cookie (支持 domain、 path、 expiry 等特性)和 缓存(支持 Cache-Control、Last-Modified、 ETag 等特性)的支持。
3.有了强大的 http 及其下载缓存的支持,image 模块的实现相当的简洁,并且支持回收被 view 持有,但被 Mem Cache 移除的图片,减少页面回退时的闪烁。
4.View 注解模块仅仅400多行代码却灵活的支持了各种 View 注入和事件绑定, 包括拥有多了方法的 listener 的支持。
1.2 其他特性
xUtils3 的一些其他特性。
1.支持超大文件(超过 2G )上传。
2.更全面的 http 请求协议支持(11种谓词),在 xUtils 中只支持10种谓词。
3.拥有更加灵活的 ORM, 和 greenDao 一致的性能。
4.更多的事件注解支持且不受混淆影响。
5.图片绑定支持 gif (受系统兼容性影响, 部分 gif 文件只能静态显示)、webp,支持圆角,圆形, 方形等裁剪,支持自动旋转。
6.从 3.5.0 开始不再包含 libwebpbackport.so,需要在 Android4.2 以下设备兼容 webp 的请使用 3.4.0 版本。
2. xUtils3 主要四大模块
xUtils 中目前包括了主要的四大模块,分别为 DbUtils 模块、ViewUtils 模块、HttpUtils 模块以及 BitmapUtils 模块,下面对这四大模块进行介绍。
2.1 DbUtils 模块
1.Android 中的 orm 框架,一行代码就可以进行增删改查。
2.支持事务,默认关闭。
3.可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK 约束等(需要混淆的时候请注解表名和列名)。
4.支持绑定外键,保存实体时外键关联实体自动保存或更新。
5.自动加载外键关联实体,支持延时加载。
6.支持链式表达查询,更直观的查询语义。
2.2 ViewUtils 模块
1.android 中的 ioc 框架,完全注解方式就可以进行 UI,资源和事件绑定。
2.新的事件绑定方式,使用混淆工具混淆后仍可正常工作。
3.目前支持常用的20种事件绑定,比如 setClickListener 等。
2.3 HttpUtils 模块
1.支持同步,异步方式的请求。
2.支持大文件上传,上传大文件不会出现 oom 内存溢出情况。
3.支持 GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT 的请求。
4.下载支持301/302重定向,支持设置是否根据 Content-Disposition 重命名下载的文件。
5.返回文本内容的请求(默认只启用了 GET 请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。
2.4 BitmapUtils 模块
1.加载 Bitmap 的时候无需考虑 Bitmap 加载过程中出现的 oom 和 android 容器快速滑动时候出现的图片错位等现象。
2.支持加载网络图片和本地图片。
3.内存管理使用 lru 算法,更好的管理 Bitmap 内存。
4.可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等。
xUtils3 中 ViewUtils 的主要作用
ViewUtils 的主要作用有两点,一是可以完全注解方式就可以进行 UI 绑定和事件绑定,另外一个就是无需 findViewById 和 setOnClickListener 等。而其中的 UI 绑定和事件绑定下面详细介绍。
1. UI 绑定
UI 绑定简而言之就是针对于控件和 View 了,分为多种绑定方法。
@ContentView(R.layout.view_acti); //setContentView 注解在activity的声明上方
@ViewInject(R.id.lv_test); //反射view
注解在一个view声明上
2. 事件绑定
事件绑定就是指监听事件的注解,比如 setOnClickListener 等。
@Event(R.id.button) //将一个自定义的方法绑定到一个 view 的事件上
至于具体的使用方法就在下面了。
xUtils3 中 ViewUtils 的使用方法
xUtils3 框架中包含了很多的工具,主要的四大模块功能也很强大,这次主要是要讲解其中的 ViewUtils 模块的使用。
1. Gradle 添加依赖
在 module 下的 build.gradle 文件下面添加对 xUtils3 的依赖。
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
compile 'com.android.support:appcompat-v7:25.2.0'
compile 'com.android.support.constraint:constraint-layout:1.0.1'
testCompile 'junit:junit:4.12'
compile 'org.xutils:xutils:3.5.0'
2. ViewUtils 初始化
在 Activity 和 Fragment 中初始化 ViewUtils 模块略有不同,所以就分开介绍了。
2.1 Activity 中初始化
在 Activity 中初始化比较简单,直接在 onCreate 中一行代码就搞定了。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
x.view().inject(this);
2.2 Fragment 中初始化
Fragment 的生命周期依赖于 Activity,另外在 Fragment 中一些方法也与 Activity 不同,所以 ViewUtils 的初始化方法也不太一样了。
private boolean injected =
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
injected =
return x.view().inject(this, inflater, container);
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (!injected) {
x.view().inject(this, this.getView());
其中 injected 是用来标识是否已经注入了 View ,如果还没有注入,在 onViewCreated 中要写入注入 View 的方法。
3. ViewUtils 绑定控件
一般在 Activity 或者 Fragment 中声明控件,都要使用方法 findViewById,如果控件一旦多了,就会很麻烦,代码要写不少,但是使用 ViewUtils 可以通过注解的方式直接进行 UI 绑定,方法也很简单。
@ViewInject(R.id.textView)
private TextView textV
4. ViewUtils 绑定布局
在为 Activity 或者 Fragment 添加布局时,我们都会使用到 setContentView(int layoutRes) 方法,在 ViewUtils 添加了直接注解布局的方法,如下。
@ContentView(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
在 Fragment 中注解方法是一样的,在 Fragment 中直接添加就好。
5. ViewUtils 绑定事件
在之前的按钮的点击事件、列表选项的 item 点击事件等,写起来代码都比较多些,而使用 ViewUtils 都可以变得简单起来,先来看下按钮的点击事件的绑定。
// 取消了之前使用方法名绑定事件的方式,使用id绑定不受混淆影响
// 支持绑定多个id @Event({R.id.id1, R.id.id2, R.id.id3})
// or @Event(value={R.id.id1, R.id.id2, R.id.id3}, parentId={R.id.pid1, R.id.pid2, R.id.pid3})
// 更多事件支持参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。
@Event(R.id.test_button)
public void testButtonClick(View v) { // 方法签名必须和接口中的要求一致
上面是按钮的点击事件的绑定,很方便,再来看看列表选项的 item 点击事件的绑定。
//选项的点击事件 OnItemClickListener
@Event(value = R.id.lv_img, type = AdapterView.OnItemClickListener.class)
private void onImageItemClick(AdapterView&?& parent, View view, int position, long id) {
ViewUtils 所支持的事件的绑定还有很多种,这里就主要介绍上面两种,更多的使用方法请参考 xUtils3 源码。
xUtils3 在 xUtils 的基础上优化了不少,ViewUtils 注解也更为的简单明了,有了 ViewUtils,我们就不用像之前一样不断的对控件进行声明,另外对于事件的处理也简化了不少,在后期的商城项目实战中,都将使用 ViewUtils 来做 UI 的绑定以及事件的绑定。
以上就是商城项目实战 | 10.1 xUtils3 详细介绍以及 ViewUtils 的使用方法的全文介绍,希望对您学习Android应用开发有所帮助.
这些内容可能对你也有帮助
更多可查看Android开发列表页。
猜您也会喜欢这些文章xUtils3源码阅读之网络模块
时间: 11:23:55
&&&& 阅读:43
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&关于xUtils3
xUtils 包含了很多实用的android工具.
xUtils 支持超大文件(超过2G)上传,更全面的http请求协议支持(11种谓词),拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响…
xUtils 最低兼容Android 4.0 (api level 14). (Android 2.3?)
xUtils3变化较多所以建立了新的项目不在旧版(/wyouflf/xUtils)上继续维护, 相对于旧版本:
HTTP实现替换HttpClient为UrlConnection, 自动解析回调泛型, 更安全的断点续传策略.
支持标准的Cookie策略, 区分domain, path…
事件注解去除不常用的功能, 提高性能.
数据库api简化提高性能, 达到和greenDao一致的性能.
图片绑定支持gif(受系统兼容性影响, 部分gif文件只能静态显示), 支持圆角, 圆形, 方形等裁剪, 支持自动旋转…
xUtils3四大模块:网络请求、图片加载、ORM框架和事件注解。本文阅读分析网络请求相关代码。
使用版本:compile ‘org.xutils:xutils:3.3.36‘
xUtils3项目地址 :
Ext.init(this);
public static class Ext {
private static A
public static void init(Application app) {
if (Ext.app == null) {
获取ApplicationCotext,方便以后调用。在Ext中有个静态代码块。详情如下:
public static class Ext {
private static TaskController taskC
TaskControllerImpl.registerInstance();
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
public static void setTaskController(TaskController taskController) {
if (Ext.taskController == null) {
Ext.taskController = taskC
public static void registerInstance() {
if (instance == null) {
synchronized (TaskController.class) {
if (instance == null) {
instance = new TaskControllerImpl();
x.Ext.setTaskController(instance);
这段静态代码块的作用是注册TaskController对象为TaskControllerImpl实例。并设置信任所有https域名。ps:还是中文注释看着爽。
RequestParams param = new RequestParams(url);
param.addParameter("name","一口仨馍");
public RequestParams(String uri) {
this(uri, null, null, null);
public RequestParams(String uri, ParamsBuilder builder, String[] signs, String[] cacheKeys) {
if (uri != null && builder == null) {
builder = new DefaultParamsBuilder();
this.uri =
this.signs =
this.cacheKeys = cacheK
this.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));
if (value instanceof List) {
} else if (value instanceof JSONArray) {
} else if (value.getClass().isArray()) {
this.bodyParams.add(new KeyValue(name, value));
this.bodyContent = value.toString();
这个时候还没有设置请求的方式,例如GET、POST等,所以mothod属性为null。而value为String类型的参数,所以name和value被以KeyValue结构的形式保存在bodyParams中。
下文以x.http().post(requestParams, monCallback&String&() {}过程为例,逐步查看xUtils3调用流程。
public static HttpManager http() {
if (Ext.httpManager == null) {
HttpManagerImpl.registerInstance();
return Ext.httpM
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 = httpM
第一次调用的时候会初始化Ext#imageManager对象为HttpManagerImpl,以后所有HTTP/HTTPS相关调用都通过HttpManagerImpl管理。
HttpManagerImpl.post()
public final class HttpManagerImpl implements HttpManager {
public &T& Callback.Cancelable post(RequestParams entity, monCallback&T& callback) {
return request(HttpMethod.POST, entity, callback);
public &T& Callback.Cancelable request(HttpMethod method, RequestParams entity, monCallback&T& callback) {
entity.setMethod(method);
Callback.Cancelable cancelable = null;
if (callback instanceof Callback.Cancelable) {
cancelable = (Callback.Cancelable)
HttpTask&T& task = new HttpTask&T&(entity, cancelable, callback);
return x.task().start(task);
这里以HttpMethod == HttpMethod.POST,entity为构造的请求参数,monCallback泛型为String查看流程。
首先设置RequestParams中请求方式为HttpMethod.POST,monCallback没有实现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,
monCallback&ResultType& callback) {
super(cancelHandler);
this.params =
this.callback =
if (callback instanceof Callback.CacheCallback) {
this.cacheCallback = (Callback.CacheCallback&ResultType&)
if (params.getExecutor() != null) {
this.executor = params.getExecutor();
if (cacheCallback != null) {
this.executor = CACHE_EXECUTOR;
this.executor = HTTP_EXECUTOR;
我们没有使用自定义的Executor(可以通过RequestParams.setExecutor()设置),所以params.getExecutor()返回是null,前文也提过CommonCallback没有实现CacheCallback,所以第一个if语句不成立,即cacheCallback为null。即,在HttpTask的构造函数中除了赋值params、callback之外,最主要的是指定了执行请求的线程池为HTTP_EXECUTOR。下面跟进看下这个HTTP_EXECUTOR。
FIFO线程池
public class PriorityExecutor implements Executor {
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 256;
private static final int KEEP_ALIVE = 1;
private static final AtomicLong SEQ_SEED = new AtomicLong(0);
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable runnable) {
return new Thread(runnable, "xTID#" + mCount.getAndIncrement());
* poolSize 工作线程数
优先级相同时, 等待队列的是否优先执行先加入的任务.
public PriorityExecutor(int poolSize, boolean fifo) {
BlockingQueue&Runnable& mPoolWorkQueue =
new PriorityBlockingQueue&Runnable&(MAXIMUM_POOL_SIZE, fifo ? FIFO_CMP : FILO_CMP);
mThreadPoolExecutor = new ThreadPoolExecutor(
MAXIMUM_POOL_SIZE,
KEEP_ALIVE,
TimeUnit.SECONDS,
mPoolWorkQueue,
sThreadFactory);
private static final Comparator&Runnable& FIFO_CMP = new Comparator&Runnable&() {
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) :
public void execute(Runnable runnable) {
if (runnable instanceof PriorityRunnable) {
((PriorityRunnable) runnable).SEQ = SEQ_SEED.getAndIncrement();
mThreadPoolExecutor.execute(runnable);
自定义了一个线程池,核心线程数是5,最大256,线程存活时间为1s,fifo(first in first out)类型。在执行Runnable之前,给PriorityRunnable的SEQ属性赋值(每次+1),并对比SEQ的值实现优先级。优先级相同时,SEQ值小的先执行。
初始化HttpTask之后,调用了x.task().start(task),x.task()返回Ext.taskController,实际返回是TaskControllerImpl对象,详见x$Ext中static代码块。所以实际上调用的是TaskControllerImpl.start()。
public final class TaskControllerImpl implements TaskController {
public &T& AbsTask&T& start(AbsTask&T& task) {
TaskProxy&T& proxy = null;
if (task instanceof TaskProxy) {
proxy = (TaskProxy&T&)
proxy = new TaskProxy&T&(task);
proxy.doBackground();
} catch (Throwable ex) {
LogUtil.e(ex.getMessage(), ex);
TaskProxy(AbsTask&ResultType& task) {
super(task);
this.task =
this.task.setTaskProxy(this);
this.setTaskProxy(null);
Executor taskExecutor = task.getExecutor();
if (taskExecutor == null) {
taskExecutor = sDefaultE
this.executor = taskE
首先,将HttpTask包装成TaskProxy,然后执行TaskProxy.doBackground()。包装成TaskProxy对象的过程无非就是设置代理任务。ps:目前没看出这个TaskProxy存在的意义,只有一个HttpTask,难道是为了可拓展?重点看TaskProxy.doBackground()。
class TaskProxy&ResultType& extends AbsTask&ResultType& {
protected final ResultType doBackground() throws Throwable {
this.onWaiting();
PriorityRunnable runnable = new PriorityRunnable(
task.getPriority(),
new Runnable() {
public void run() {
if (callOnCanceled || TaskProxy.this.isCancelled()) {
throw new Callback.CancelledException("");
TaskProxy.this.onStarted();
if (TaskProxy.this.isCancelled()) {
throw new Callback.CancelledException("");
task.setResult(task.doBackground());
TaskProxy.this.setResult(task.getResult());
if (TaskProxy.this.isCancelled()) {
throw new Callback.CancelledException("");
TaskProxy.this.onSuccess(task.getResult());
} catch (Callback.CancelledException cex) {
TaskProxy.this.onCancelled(cex);
} catch (Throwable ex) {
TaskProxy.this.onError(ex, false);
} finally {
TaskProxy.this.onFinished();
this.executor.execute(runnable);
return null;
this.onWaiting()的作用是将任务置为等待状态,对阅读代码无影响,继续。PriorityRunnable实现了Runnable接口,为传递进来的Runnable对象添加了priority属性,priority默认为3(优先级为0、1、2、3、4、5、6,数字越小,优先级越高)。之后会将PriorityRunnable添加进HTTP_EXECUTOR并依据优先级执行。callOnCanceled默认为false,之后设置任务状态为started,回调onStarted()方法。这些都不是重点,重点在下面两行:
// 执行task, 得到结果.
task.setResult(task.doBackground())
TaskProxy.this.setResult(task.getResult())
正室不死,代理终究还是代理。在这里调用了HttpTask.doBackground()。看样子真正的执行请求都在这里,跟进。
protected ResultType doBackground() throws Throwable {
ResultType result =
// 获取LoadType
resolveLoadType();
// 创建真正的网络请求
request = createNewRequest();
// 是否重试,默认2次
boolean retry =
// 已经重试的次数
int retryCount = 0;
Throwable exception =
HttpRetryHandler retryHandler = this.params.getHttpRetryHandler();
if (retryHandler == null) {
retryHandler = new HttpRetryHandler();
// 设置最大重试次数
retryHandler.setMaxRetryCount(this.params.getMaxRetryCount());
Object cacheResult =
if (trustCache == null) {
trustCache =
// 发起请求
while (retry) {
if (this.isCancelled()) {
throw new Callback.CancelledException("cancelled before request");
// 由loader发起请求, 拿到结果.
this.request.close(); // retry 前关闭上次请求
clearRawResult();
// 开始请求工作
LogUtil.d("load: " + this.request.getRequestUri());
requestWorker = new RequestWorker();
// 真正开始请求
requestWorker.request();
if (requestWorker.ex != null) {
throw requestWorker.
rawResult = requestWorker.
} catch (Throwable ex) {
clearRawResult();
if (prepareCallback != null) {
result = (ResultType) rawR
} catch (HttpRedirectException redirectEx) {
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.
default: {
exception =
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 =
有些长,我们一点点的看。首先,ResultType肯定是我们传递进来的泛型String。resolveLoadType()为loadType赋值,港真,这里的loadType和ResultType是一样的。没搞明白为什么ResultType能解决的事情,又定义了一个loadType属性。难道是为了好区分ResultType是要返回的类型,loadType是要解析的类型?实际上两者是一样的,在这里都是String。非要说区别的话,ResultType是String,loadType为String.class。
请求参数的处理
private UriRequest createNewRequest() throws Throwable {
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);
在params.init()中,主要是设置信任所有证书。主要关注点在下面的创建UriRequest对象。
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 = SCHEME_CLS_MAP.get(scheme);
if (cls != null) {
Constructor&? extends UriRequest& constructor
= cls.getConstructor(RequestParams.class, Class.class);
return constructor.newInstance(params, loadType);
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);
throw new IllegalArgumentException("The url not be support: " + uri);
throw new IllegalArgumentException("The url not be support: " + uri);
获取scheme,这里以https分析。这里好像还整个缓存Map,不管有没有缓存,返回的都是HttpRequest对象,只是来源不一样,这里就不具体分析这个存取的过程。实例化HttpRequest的时候,还有些文章。下面跟进。
public class HttpRequest extends UriRequest {
HttpRequest(RequestParams params, Type loadType) throws Throwable {
super(params, loadType);
public abstract class UriRequest implements Closeable {
protected final Loader&?&
UriRequest(RequestParams params, Type loadType) throws Throwable {
this.params =
this.queryUrl = buildQueryUrl(params);
this.loader = LoaderFactory.getLoader(loadType, params);
运用工厂模式,通过LoaderFactory获取了一个Loader对象,这个对象在后面有很大的作用。先跟进看下。
public final class LoaderFactory {
private LoaderFactory() {
private static final HashMap&Type, Loader& converterHashMap = new HashMap&Type, Loader&();
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);
result = result.newInstance();
result.setParams(params);
传递进来的type为String.class,所以调用StringLoader.newInstance()。这里并不是反射,newInstance()只是个普通方法,返回StringLoader对象。拓展的有些远了,回到HttpTask.doBackground()。大概屡一下思路:现在已经将解析出loadType为String.class,HttpRequest对象赋值给request,并在在实例化HttpRequest对象的过程中设置Loader
在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次数进行处理。下面是整个流程的分析。
// 发起请求
while (retry) {
requestWorker = new RequestWorker();
requestWorker.request();
if (requestWorker.ex != null) {
throw requestWorker.
} catch (Throwable ex) {
} catch (HttpRedirectException redirectEx) {
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.
default: {
retry = retryHandler.canRetry(this.request, exception, ++retryCount);
private final class RequestWorker {
/*private*/ O
/*private*/ T
private RequestWorker() {
public void request() {
this.result = request.loadResult();
} catch (Throwable ex) {
if (this.ex != null) {
throw this.
} catch (Throwable ex) {
if (errorCode == 301 || errorCode == 302) {//重定向
HttpTask.this.params = redirectP
HttpTask.this.request = createNewRequest();
this.ex = new HttpRedirectException(errorCode, httpEx.getMessage(), httpEx.getResult());
} finally {
正常的请求失败,会通过retryHandler.canRetry(),将retry置为true,最多执行两次retry。让我疑惑的地方在于重定向的处理。在requestWorker.request()中,如果有重定向,会抛出HttpRedirectException。但是在HttpTask#doBackground()中
if (requestWorker.ex != null) {
throw requestWorker.
} catch (Throwable ex) {
clearRawResult();
if (this.isCancelled()) {
throw new Callback.CancelledException("cancelled during request");
这里向上转型为Throwable并抛出,从而进入外层的
} catch (HttpRedirectException redirectEx) {
retry = true;
LogUtil.w("Http Redirect:" + params.getUri());
} catch (Throwable ex) {
switch (this.request.getResponseCode()) {
return null;
default: {
exception =
if (this.isCancelled() && !(exception instanceof Callback.CancelledException)) {
exception = new Callback.CancelledException("canceled by user");
retry = retryHandler.canRetry(this.request, exception, ++retryCount);
正常应该进入HttpRedirectException的,但是向上转型成Throwable之后就只能进入下面的catch代码块中。那么HttpRedirectException存在的意义在哪里?希望明白的给指点下。
真正的请求
requestWorker = new RequestWorker();
requestWorker.request();
HttpTask.doBackground()中请求其实只有这两行代码。RequestWorker是HttpTask的一个final内部类,requestWorker.request()方法内部会设置拦截器,处理重定向等,这些暂时不是关注的重点。总之先把流程跑通再说。
private final class RequestWorker {
/*private*/ O
public void request() {
this.result = request.loadResult();
request实际上是HttpRequest对象。
public class HttpRequest extends UriRequest {
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);
class StringLoader extends Loader&String& {
public String load(final UriRequest request) throws Throwable {
request.sendRequest();
return this.load(request.getInputStream());
public String load(final InputStream in) throws Throwable {
resultStr = IOUtil.readStr(in, charset);
return resultS
经过层层调用最终调用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中。
public final synchronized void cancel() {
if (!this.isCancelled) {
this.isCancelled = true;
cancelWorks();
if (cancelHandler != null && !cancelHandler.isCancelled()) {
cancelHandler.cancel();
if (this.state == State.WAITING || (this.state == State.STARTED && isCancelFast())) {
if (taskProxy != null) {
taskProxy.onCancelled(new Callback.CancelledException("cancelled by user"));
taskProxy.onFinished();
} else if (this instanceof TaskProxy) {
this.onCancelled(new Callback.CancelledException("cancelled by user"));
this.onFinished();
AbsTask实现了Cancelable接口,所以这里的cancelHandler不为null,但是cancelHandler.isCancelled()返回true,所以不会循环调用cancelHandler.cancel()。任务被创建后就进入了WAITING状态,所以会调用TaskProxy.onCancelled()和TaskProxy.onFinished()。在这两个回调方法中分别通过Hanlder在主线程中调用HttpTask的onCanclled()和onFinished()方法,之后再调用接口回调中的onCanclled()和onFinished()方法。需要注意的是HttpTask.onFinished()方法。
protected void onFinished() {
if (tracker != null) {
tracker.onFinished(request);
x.task().run(new Runnable() {
public void run() {
closeRequestSync();
callback.onFinished();
private void closeRequestSync() {
clearRawResult();
IOUtil.closeQuietly(request);
public static void closeQuietly(Closeable closeable) {
if (closeable != null) {
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();
在调用callback.onFinished()的同时异步执行线程,清除请求结果和关闭链接。这个过程对调用者来说是异步的无感知的。
xUtils3使用PriorityExecutor(FIFO线程池)+PriorityRunnable(带优先级的Runnable)实现网络请求。
通过传入MainLooper的Handler实现由子线程到主线程的切换,并调用相应的回调方法。
支持retry,默认2次。
通过给Task设置不同状态,实现不同状态下的处理,主要是为了实现cancle()。
自带拓展了不同类型的Callback和Loader,满足日常开发(特殊需求可仿照实现)。
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&国之画&&&& &&
版权所有 京ICP备号-2
迷上了代码!

我要回帖

更多关于 百度热心网友 的文章

 

随机推荐