自己使用xUtils3后总结一下下

时间:2022-12-11 09:36:29

前言:写这文章只是为了记录下,方便自己以后查找。
参考:http://blog.csdn.net/tyk9999tyk/article/details/53306035
http://blog.csdn.net/l_xiaole/article/details/52182568

1)首先大概介绍下xUtils3

个人是17年初次接触xUtils的,使用过了感觉还不错,接下来稍稍介绍下让更多人知道这框架
xUtils是目前功能比较完善的一个Android开源框架,最近官网又发布了xUtil3.5.0,在增加新功能的同时又提高了框架的性能,下面来看看官方(https://github.com/wyouflf/xUtils3)对xUtils3的介绍:

  • xUtils包含了很多实用的android工具;
  • xUtils支持超大文件(超过2G)上传,更全面的http请求协议支持(11种谓词),拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响;
  • xUtils 最低兼容Android 4.0 (api level 14);
  • xUtils3变化较多所以建立了新的项目不在旧版(github.com/wyouflf/xUtils)上继续维护, 相对于旧版本:

    • HTTP实现替换HttpClient为UrlConnection, 自动解析回调泛型, 更安全的断点续传策略;
    • 支持标准的Cookie策略, 区分domain, path;
    • 事件注解去除不常用的功能, 提高性能;
    • 数据库api简化提高性能, 达到和greenDao一致的性能;
    • 图片绑定支持gif(受系统兼容性影响, 部分gif文件只能静态显示), webp; 支持圆角, 圆形, 方形等裁剪, 支持自动旋转。
  • xUtils 包含了orm, http(s), image, view注解, 但依然很轻量级(246K), 并且特性强大, 方便扩展:
    稳定的基石:AbsTask和统一的回调接口Callback, 任何异常, 即使你的回调方法实现有异常都会进入onError, 任何情况下 onFinished总会让你知道任务结束了.
    基于高效稳定的orm工具, http模块得以更方便的实现cookie(支持domain, path, expiry等特性)和
    缓存(支持Cache-Control, Last-Modified, ETag等特性)的支持.
    有了强大的http及其下载缓存的支持, image模块的实现相当的简洁, 并且支持回收被view持有, 但被Mem Cache移除的图片, 减少页面回退时的闪烁..
    view注解模块仅仅400多行代码却灵活的支持了各种View注入和事件绑定, 包括拥有多了方法的listener的支持.

- 目前xUtils主要有四大模块:

  • DbUtils模块:

    • android中的orm框架,一行代码就可以进行增删改查; 支持事务,默认关闭;

    • 可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名);

    • 支持绑定外键,保存实体时外键关联实体自动保存或更新;

    • 自动加载外键关联实体,支持延时加载;

    • 支持链式表达查询,更直观的查询语义,参考下面的介绍或sample中的例子。

  • ViewUtils模块:

    • android中的ioc框架,完全注解方式就可以进行UI,资源和事件绑定;
    • 新的事件绑定方式,使用混淆工具混淆后仍可正常工作;
    • 目前支持常用的20种事件绑定,参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。
  • HttpUtils模块:

    • 支持同步,异步方式的请求;
    • 支持大文件上传,上传大文件不会oom;
    • 支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT请求;
    • 下载支持301/302重定向,支持设置是否根据Content-Disposition重命名下载的文件;
    • 返回文本内容的请求(默认只启用了GET请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。
  • BitmapUtils模块:

    • 加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象;
    • 支持加载网络图片和本地图片;
    • 内存管理使用lru算法,更好的管理bitmap内存;
    • 可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等…

2)大概了解后接下来看看怎么将xUtils3导入项目

  • Android Studio导入其实很简单,使用Gradle构建时添加一下依赖即可:
    compile 'org.xutils:xutils:3.3.42'
  • eclipse可以点击下面链接下载aar文件, 然后用zip解压,取出jar包和so文件。

Github下载:https://github.com/wyouflf/xUtils3
JCenter下载:http://jcenter.bintray.com/org/xutils/xutils/
Maven下载1:http://central.maven.org/maven2/org/xutils/xutils/
Maven下载2:http://repo1.maven.org/maven2/org/xutils/xutils/

  • 所需要的权限
<uses-permission android:name="android.permission.INTERNET" /> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  • 创建Application,初始化xUtils“
public class MyApplication extends Application {

@Override
public void onCreate() {
super.onCreate();
//初始化
x.Ext.init(this);
// 设置是否输出debug
x.Ext.setDebug(true);
}
}
  • 在AndroidManifest文件中注册MyApplication
<application
android:name=".MyApplication "
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">

3)xUtils3注解模块

Activity与Fragment绑定视图注解:首先我们要在onCreate()里面添加 x.view().inject(this);
之后就不必须要我们设置视图:setContentView(R.layout.activity_main);直接在Activity上这样写:

//Activity注解
@ContentView(R.layout.activity_main)
public class MainActivity extends BaseActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
x.view().inject(this);//注入view和事件
...
}
}
//Fragment注解
@ContentView(R.layout.fragment_main_home)
public class HomeFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
return x.view().inject(this, inflater, container);
}

绑定控件的注解:

    // xUtils的view注解要求必须提供id
@ViewInject(R.id.linearlayout)
private LinearLayout linearlayout;

@ViewInject(R.id.imageView)
private ImageView imageView;

点击事件的注解:(注意方法必须私有限定)

  /**
* 普通点击事件
*
* @param view
*/

@Event(R.id.nav_top_right_btn)
private void navTopRightBtn(View view) {
//点击逻辑
}

/**
* RadioGroup点击事件
* value为对应控件id且支持数组: value={id1, id2, id3},type为点击类型
* @param group
* @param checkedId
*/

@Event(value = R.id.main_change_group, type = RadioGroup.OnCheckedChangeListener.class)
private void mainChange(RadioGroup group, @IdRes int checkedId) {
//点击逻辑
}

4)xUtils3网络模块的使用

GET请求:

DefaultParams params = new DefaultParams(url);
//params.addQueryStringParameter("username","pixiaozhi");//带参数的请求,视情况可以不写
//params.addQueryStringParameter("password","123456");
x.http().get(params, new RequestCallBack<String>()
public boolean onSuccess(ServerResponse result) {
//成功后在此解析数据
return false;
}
//请求失败后的回调方法
@Override
public void onError(Throwable ex, boolean isOnCallback) {
}
//主动调用取消请求的回调方法
@Override
public void onCancelled(CancelledException cex) {
}
//最终都会执行的方法
@Override
public void onFinished() {
}
});

POST请求:

      RequestParamsparams = new RequestParams(url);
params.addBodyParameter("account", "pixiaozhi");
params.addBodyParameter("password", "123456");
//params.addBodyParameter("file",new File(path));上传文件
x.http().post(params, new Callback.CommonCallback<String>() {
@Override
public boolean onSuccess(ServerResponse result) {
//成功后在此解析数据
return false;
}
//请求失败后的回调方法
@Override
public void onError(Throwable ex, boolean isOnCallback) {
}
//主动调用取消请求的回调方法
@Override
public void onCancelled(CancelledException cex) {
}
//最终都会执行的方法
@Override
public void onFinished() {
}
});
RequestParams params = new RequestParams(url);
//自定义保存路径,Environment.getExternalStorageDirectory():SD卡的根目录
params.setSaveFilePath(Environment.getExternalStorageDirectory()+"/myapp/");
//自动为文件命名
params.setAutoRename(true);
x.http().post(params, new Callback.ProgressCallback<File>() {
@Override
public void onSuccess(ResponseInfo<File> responseInfo) {
//以安装包为例,apk下载完成后,调用系统的安装方法
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(result), "application/vnd.android.package-archive");
getActivity().startActivity(intent);
}
//请求失败后的回调方法
@Override
public void onError(Throwable ex, boolean isOnCallback) {
}
//主动调用取消请求的回调方法
@Override
public void onCancelled(CancelledException cex) {
}
//最终都会执行的方法
@Override
public void onFinished() {
}
//网络请求之前回调
@Override
public void onWaiting() {
}
//网络请求开始的时候回调
@Override
public void onStarted() {
}
//下载进度回调的方法
@Override
public void onLoading(long total, long current, boolean isDownloading) {
//当前进度和文件总大小
Log.i("JAVA","current:"+ current +",total:"+total);
}
});

5)xUtils3图片模块的使用

//获取图片控件
@ViewInject(R.id.image1)
ImageView image1;
@ViewInject(R.id.image2)
ImageView image2;
@ViewInject(R.id.image3)
ImageView image3;

//图片地址,为了方便随便写的地址
String[] urls={
"http://img.android.com/1.jpg"
"http://img.android.com/2.jpg"
"http://img.android.com/3.jpg"}

//设置图片
private void setImageView() {
/**
* 通过ImageOptions.Builder().set方法设置图片的属性
*/

ImageOptions options = new ImageOptions.Builder().setFadeIn(true).build(); //淡入效果
//ImageOptions.Builder()的一些其他属性:
//.setCircular(true) //设置图片显示为圆形
//.setSquare(true) //设置图片显示为正方形
//setCrop(true).setSize(200,200) //设置大小
//.setAnimation(animation) //设置动画
//.setFailureDrawable(Drawable failureDrawable) //设置加载失败的动画
//.setFailureDrawableId(int failureDrawable) //以资源id设置加载失败的动画
//.setLoadingDrawable(Drawable loadingDrawable) //设置加载中的动画
//.setLoadingDrawableId(int loadingDrawable) //以资源id设置加载中的动画
//.setIgnoreGif(false) //忽略Gif图片
//.setParamsBuilder(ParamsBuilder paramsBuilder) //在网络请求中添加一些参数
//.setRaduis(int raduis) //设置拐角弧度
//.setUseMemCache(true) //设置使用MemCache,默认true

/**
* 加载图片的3个bind方法
*/

//普通绑定
x.image().bind(image1, urls[0]);
//带参数绑定
x.image().bind(image2, urls[1], options);
//含回调方法的绑定
x.image().bind(image3, urls[2], options, new Callback.CommonCallback<drawable>() {
@Override
public void onSuccess(Drawable result) {
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
}
@Override
public void onCancelled(CancelledException cex) {
}
@Override
public void onFinished() {
}
});

/**
* loadDrawable()方法加载图片
*/

Callback.Cancelable cancelable = x.image().loadDrawable(urls[0], options, new Callback.CommonCallback<drawable>() {
@Override
public void onSuccess(Drawable result) {
image3.setImageDrawable(result);
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
}
@Override
public void onCancelled(CancelledException cex) {
}
@Override
public void onFinished() {
}
});
//主动取消loadDrawable()方法
//cancelable.cancel();

/**
* loadFile()方法
* 应用场景:当我们通过bind()或者loadDrawable()方法加载了一张图片后,
* 它会保存到本地文件中,那当我需要这张图片时,就可以通过loadFile()方法进行查找。
* urls[0]:网络地址
*/

x.image().loadFile(urls[0],options,new Callback.CacheCallback<file>(){
@Override
public boolean onCache(File result) {
//在这里可以做图片另存为等操作
Log.i("JAVA","file:"+result.getPath()+result.getName());
return true; //本地缓存返回true
}
@Override
public void onSuccess(File result) {
Log.i("JAVA","file");
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
}
@Override
public void onCancelled(CancelledException cex) {
}
@Override
public void onFinished() {
}
});
}

6)数据库模块的使用

/**
* 获取数据库管理工具
*
* @param context
* @return
*/

public static DbManager dbManager(Context context) {
try {
DbManager.DaoConfig daoConfig = new DbManager.DaoConfig()//
.setDbName(AppConstants.APP)//设置数据库名称
.setDbDir(FileHelper.getDataFilesDir(context))//不设置dbDir时, 默认存储在app的私有目录.
.setDbVersion(1)//设置数据库版本,之前遇到过一次坑,就是当我app的升级版本且数据库里面有字段更改,会造成默认读取的是之前的数据库从而造成很多异常/(ㄒoㄒ)/~~,当时处理是更改数据库名字,后面发现可以通过这个解决;比如你的app第一版数据库版本设置的是1,如果第二版数据库字段有变动,那就直接把版本设置成2就可以了,这样会删除你app里面之前的数据库
.setDbOpenListener(new DbManager.DbOpenListener() {
@Override
public void onDbOpened(DbManager db) {
db.getDatabase().enableWriteAheadLogging(); // 开启WAL, 对写入加速提升巨大
}
});

return x.getDb(daoConfig);
} catch (Exception e) {
e.printStackTrace();
//自己做了个项目在小米的红米和红米加强版这两款手机上由于磁盘不够会抛SQLiteFullException异常,这里索性把异常都抛了
Toast.makeText(context, "磁盘空间不足", Toast.LENGTH_SHORT).show();
return null;
}

}

创建数据库表单:

//插入数据库操作的时候会判断是否存在这张表,如果不存在就会去创建
@Table(name = "user_info")
public class UserInfo implements Serializable {
@Column(name = "id", isId = true)
private Integer id;//用户ID

@Column(name = "msisdn")
private String msisdn; //用户账号/手机号

@Column(name = "username")
private String username; //用户名

@Column(name = "driverType")
private Integer driverType;//驾证类型

@Column(name = "subjectType")
private Integer subjectType; //科目类型

@Column(name = "areaCode")
private String areaCode; //区域代码

@Column(name = "address")
private String address; //所在地址

@Column(name = "sex")
private Integer sex = 0; //性别

@Column(name = "status")
private Integer status;//用户状态

@Column(name = "overdueTime")
private Date overdueTime; //购买过期时间

@Column(name = "token")
private String token; //登录唯一识别码

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getMsisdn() {
return msisdn;
}

public void setMsisdn(String msisdn) {
this.msisdn = msisdn;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public Integer getDriverType() {
return driverType;
}

public void setDriverType(Integer driverType) {
this.driverType = driverType;
}

public Integer getSubjectType() {
return subjectType;
}

public void setSubjectType(Integer subjectType) {
this.subjectType = subjectType;
}

public String getAreaCode() {
return areaCode;
}

public void setAreaCode(String areaCode) {
this.areaCode = areaCode;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

public Integer getSex() {
return sex;
}

public void setSex(Integer sex) {
this.sex = sex;
}

public Integer getStatus() {
return status;
}

public void setStatus(Integer status) {
this.status = status;
}

public Date getOverdueTime() {
return overdueTime;
}

public void setOverdueTime(Date overdueTime) {
this.overdueTime = overdueTime;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}

//由于我实现了序列化,所以封装了个解析方法
public static UserInfo formJson(JSONObject json) {
if (json == null) return null;
UserInfo fragment = new UserInfo();

fragment.id = JsonUtil.optInteger(json, "id");
fragment.msisdn = JsonUtil.optString(json, "msisdn");
fragment.username = JsonUtil.optString(json, "username");
fragment.driverType = JsonUtil.optInteger(json, "driverType");
fragment.subjectType = JsonUtil.optInteger(json, "subjectType");
fragment.areaCode = JsonUtil.optString(json, "areaCode");
fragment.address = JsonUtil.optString(json, "address");
fragment.sex = JsonUtil.optInteger(json, "sex");
fragment.status = JsonUtil.optInteger(json, "status");
fragment.overdueTime = JsonUtil.optDate(json, "overdueTime");
fragment.token = JsonUtil.optString(json, "token");

return fragment;
}

/**
* 验证是否过期
*
* @return
*/

public boolean validateOverdue() {
if(DXApplication.date != null){
if (getOverdueTime() == null || getOverdueTime().before(DXApplication.date)) {
return false;
} else {
return true;
}
}else {
if (getOverdueTime() == null || getOverdueTime().before(new Date())) {
return false;
} else {
return true;
}
}

}
//写的个克隆方法,当作临时字段存储
public UserInfo clone() {
UserInfo info = new UserInfo();
info.id = this.id;
info.msisdn = this.msisdn;
info.username = this.username;
info.driverType = this.driverType;
info.subjectType = this.subjectType;
info.areaCode = this.areaCode;
info.address = this.address;
info.sex = this.sex;
info.status = this.status;
info.overdueTime = this.overdueTime;
info.token = this.token;

return info;
}
}

xUtils的数据库访问接口:

/**
* 数据库访问接口
*/

public interface DbManager extends Closeable {

DaoConfig getDaoConfig();

SQLiteDatabase getDatabase();

/**
* 保存实体类或实体类的List到数据库,
* 如果该类型的id是自动生成的, 则保存完后会给id赋值.
*
* @param entity
* @return
* @throws DbException
*/

boolean saveBindingId(Object entity) throws DbException;

/**
* 保存或更新实体类或实体类的List到数据库, 根据id对应的数据是否存在.
*
* @param entity
* @throws DbException
*/

void saveOrUpdate(Object entity) throws DbException;

/**
* 保存实体类或实体类的List到数据库
*
* @param entity
* @throws DbException
*/

void save(Object entity) throws DbException;

/**
* 保存或更新实体类或实体类的List到数据库, 根据id和其他唯一索引判断数据是否存在.
*
* @param entity
* @throws DbException
*/

void replace(Object entity) throws DbException;

///////////// delete
void deleteById(Class<?> entityType, Object idValue) throws DbException;

void delete(Object entity) throws DbException;

void delete(Class<?> entityType) throws DbException;

int delete(Class<?> entityType, WhereBuilder whereBuilder) throws DbException;

///////////// update
void update(Object entity, String... updateColumnNames) throws DbException;

int update(Class<?> entityType, WhereBuilder whereBuilder, KeyValue... nameValuePairs) throws DbException;

///////////// find
<T> T findById(Class<T> entityType, Object idValue) throws DbException;

<T> T findFirst(Class<T> entityType) throws DbException;

<T> List<T> findAll(Class<T> entityType) throws DbException;

<T> Selector<T> selector(Class<T> entityType) throws DbException;

DbModel findDbModelFirst(SqlInfo sqlInfo) throws DbException;

List<DbModel> findDbModelAll(SqlInfo sqlInfo) throws DbException;

///////////// table

/**
* 获取表信息
*
* @param entityType
* @param <T>
* @return
* @throws DbException
*/

<T> TableEntity<T> getTable(Class<T> entityType) throws DbException;

/**
* 删除表
*
* @param entityType
* @throws DbException
*/

void dropTable(Class<?> entityType) throws DbException;

/**
* 添加一列,
* 新的entityType中必须定义了这个列的属性.
*
* @param entityType
* @param column
* @throws DbException
*/

void addColumn(Class<?> entityType, String column) throws DbException;

///////////// db

/**
* 删除库
*
* @throws DbException
*/

void dropDb() throws DbException;

/**
* 关闭数据库,
* xUtils对同一个库的链接是单实例的, 一般不需要关闭它.
*
* @throws IOException
*/

void close() throws IOException;

///////////// custom
int executeUpdateDelete(SqlInfo sqlInfo) throws DbException;

int executeUpdateDelete(String sql) throws DbException;

void execNonQuery(SqlInfo sqlInfo) throws DbException;

void execNonQuery(String sql) throws DbException;

Cursor execQuery(SqlInfo sqlInfo) throws DbException;

Cursor execQuery(String sql) throws DbException;

public interface DbOpenListener {
void onDbOpened(DbManager db);
}

public interface DbUpgradeListener {
void onUpgrade(DbManager db, int oldVersion, int newVersion);
}

public interface TableCreateListener {
void onTableCreated(DbManager db, TableEntity<?> table);
}

public static class DaoConfig {
private File dbDir;
private String dbName = "xUtils.db"; // default db name
private int dbVersion = 1;
private boolean allowTransaction = true;
private DbUpgradeListener dbUpgradeListener;
private TableCreateListener tableCreateListener;
private DbOpenListener dbOpenListener;

public DaoConfig() {
}

public DaoConfig setDbDir(File dbDir) {
this.dbDir = dbDir;
return this;
}

public DaoConfig setDbName(String dbName) {
if (!TextUtils.isEmpty(dbName)) {
this.dbName = dbName;
}
return this;
}

public DaoConfig setDbVersion(int dbVersion) {
this.dbVersion = dbVersion;
return this;
}

public DaoConfig setAllowTransaction(boolean allowTransaction) {
this.allowTransaction = allowTransaction;
return this;
}

public DaoConfig setDbOpenListener(DbOpenListener dbOpenListener) {
this.dbOpenListener = dbOpenListener;
return this;
}

public DaoConfig setDbUpgradeListener(DbUpgradeListener dbUpgradeListener) {
this.dbUpgradeListener = dbUpgradeListener;
return this;
}

public DaoConfig setTableCreateListener(TableCreateListener tableCreateListener) {
this.tableCreateListener = tableCreateListener;
return this;
}

public File getDbDir() {
return dbDir;
}

public String getDbName() {
return dbName;
}

public int getDbVersion() {
return dbVersion;
}

public boolean isAllowTransaction() {
return allowTransaction;
}

public DbOpenListener getDbOpenListener() {
return dbOpenListener;
}

public DbUpgradeListener getDbUpgradeListener() {
return dbUpgradeListener;
}

public TableCreateListener getTableCreateListener() {
return tableCreateListener;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

DaoConfig daoConfig = (DaoConfig) o;

if (!dbName.equals(daoConfig.dbName)) return false;
return dbDir == null ? daoConfig.dbDir == null : dbDir.equals(daoConfig.dbDir);
}

@Override
public int hashCode() {
int result = dbName.hashCode();
result = 31 * result + (dbDir != null ? dbDir.hashCode() : 0);
return result;
}

@Override
public String toString() {
return String.valueOf(dbDir) + "/" + dbName;
}
}
}

xUtils提供很多已经封装增删改查方法可以直接调用使用,具体可以查看这篇文章

http://blog.csdn.net/l_xiaole/article/details/52182568

,同时我们也可以自己写Sql语句:

SqlInfo sqlInfo = new SqlInfo();
sqlInfo.setSql("DELETE FROM t_question_history WHERE msisdn = ? AND now_driver_type=? AND now_subject_type=? ");
sqlInfo.addBindArg(new KeyValue("1", msisdn));
sqlInfo.addBindArg(new KeyValue("2", userInfo.getDriverType()));
sqlInfo.addBindArg(new KeyValue("3", userInfo.getSubjectType()));
//这里需要注意的是key值可以随便自己取但是一定要保证参数值要和sql语句里面要传的值(?)一一对应,顺序不能乱。
try {
dbManager.executeUpdateDelete(sqlInfo);//这里以更新删除为例,同理可以做增删改查操作
} catch (Exception e) {
e.printStackTrace();
}

谢谢大家观看,由于初次发表可能许多地方有不足请大家见谅,也希望如果有什么错请各位大神指证,小白在此感激不敬,最后诚心祝愿大家写代码一次通过,没有bug(^_^)!!!