一直都听闻有个xUtils,但是没有使用过。最近有一个小项目,需要快速开发,工期较短,所以,就想到了xUtils。
目前xUtils已经发布到xUtils3,所以,我们就按照xUtils3的规范来开发。xUtils系列框架提供的功能主要有四大模块,ViewUtils模块、BitmapUtils模块、DbUtils模块、HttpUtils模块。下面,我们就从这4方面介绍具体xUtils3的使用。
一、使用前配置。
使用Android Studio开发时,我们需要在build.gradle文件中添加依赖:
compile 'org.xutils:xutils:3.5.0'
(如果还是使用Eclipse,需要自行下载jar包导入至项目中即可。本篇文章是以Android Studio开发)
并且我们还需要在AndroidManifest.xml文件中添加网络权限,具体权限如下,
二、使用。
创建Application,在它的onCreate()方法中添加初始化代码,具体代码如下,
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
x.Ext.init(this);
x.Ext.setDebug(false); // 是否输出debug日志,开启debug会影响性能
}
}
记得要在AndroidManifest.xml文件中添加我们自定义的MyApplication,代码如下,
PS:我们通过源码看看x类的描述,
/**
* Created by wyouflf on 15/6/10.
* 任务控制中心, http, image, db, view注入等接口的入口.
* 需要在在application的onCreate中初始化: x.Ext.init(this);
*/
public final class x
x.Ext.init(this);
public static void init(Application app) {
TaskControllerImpl.registerInstance();//实例化异步任务的管理类
if (Ext.app == null) {
Ext.app = app;
}
}
三.ViewUtils模块。
(1).android中的ioc框架,完全注解方式就可以进行UI,资源和事件绑定;
(2).新的事件绑定方式,使用混淆工具混淆后仍可正常工作;
(3).目前支持常用的20种事件绑定,参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。
使用注解可以简化许多重复的工作。记得要使用注解功能,需要先初始化注解模块!
1.在Activity中使用注解
在Activity的onCreate()中需要初始化注解框架,具体写法如下,
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
x.view().inject(this);//初始化注解模块
}
加载布局,
@ContentView(R.layout.activity_main)
绑定控件,
@ViewInject(R.id.tv_msg)
TextView mTvMsg;
@ViewInject(R.id.btn_start)
Button mStartBtn;
事件监听,
@Event(value=R.id.btn_start,type = View.OnClickListener.class)
private void startLoading(View v){
Toast.makeText(this, "startLoading", Toast.LENGTH_SHORT).show();
}
使用@Event事件注解事,需要注意以下几点,
* 1. 方法必须私有限定,
* 2. 方法参数形式必须和type对应的Listener接口一致.
* 3. 注解参数value支持数组: value={id1, id2, id3}
* 4. 其它参数说明见{@link org.xutils.event.annotation.Event}类的说明.
* 5. type,可选参数, 默认是View.OnClickListener.class,需要根据实际情况来确定具体的值,例如长按事件,type = View.OnLongClickListener.class.
2.在Fragment中使用注解
在Fragment中初始化注解框架,与Activity稍有不同,
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return x.view().inject(this,inflater,container);
}
在Fragment中使用注解和Activity中是一样的,此处就不在细说。
@ContentView(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
@ViewInject(R.id.tv_msg)
TextView mTvMsg;
@ViewInject(R.id.btn_start)
Button mStartBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
x.view().inject(this);
}
@Event(value=R.id.btn_start,type = View.OnLongClickListener.class)
private void startLoading(View v){
Toast.makeText(this, "startLoading", Toast.LENGTH_SHORT).show();
}
}
有关注解使用,就到这儿!如果还想了解更多,可以去 xUtils的github上看它们的sample。
四.BitmapUtils模块。
(1).加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象;
(2).支持加载网络图片和本地图片;
(3).内存管理使用lru算法,更好的管理bitmap内存;
(4).可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等...
图片加载,xUtils提供多种加载图片的方式,本地加载、缓存加载、网络加载,支持加载gif等,如下所示,
x.image().bind(imageView, url, imageOptions);
// assets file
x.image().bind(imageView, "assets://test.gif", imageOptions);
// local file
x.image().bind(imageView, new File("/sdcard/test.gif").toURI().toString(), imageOptions);
x.image().bind(imageView, "/sdcard/test.gif", imageOptions);
x.image().bind(imageView, "file:///sdcard/test.gif", imageOptions);
x.image().bind(imageView, "file:/sdcard/test.gif", imageOptions);
x.image().bind(imageView, url, imageOptions, new Callback.CommonCallback() {...});
x.image().loadDrawable(url, imageOptions, new Callback.CommonCallback() {...});
// 用来获取缓存文件
x.image().loadFile(url, imageOptions, new Callback.CommonCallback() {...});
上面的方法中都有一个ImageOptions参数,我们看看这是什么鬼!ImageOptions可以设置一些属性,方便加载图片,下面是它的基本属性设置,
.setSize(DensityUtil.dip2px(60),DensityUtil.dip2px(60))//设置图片大小
.setRadius(DensityUtil.dip2px(5))//圆角半径
.setCrop(true)//是否对图片进行裁剪,如果ImageView的大小不是定义为wrap_content, 不要crop.
.setImageScaleType()//设置图片的缩放格式
.setFadeIn(true)//设置淡入效果
.setLoadingDrawableId(R.mipmap.ic_launcher)//设置加载过程中显示的图片
.setFailureDrawableId(R.mipmap.ic_launcher)//设置加载失败显示的图片
.setUseMemCache(true)//设置使用缓存
.setCircular(true)//设置图片显示为圆形
.setSquare(true);//设置图片显示为正方形
.setIgnoreGif(true)//设置支持gif
.setAnimation()//设置动画
下面展示使用用例,
...
@ViewInject(R.id.iv_pic)
ImageView mIvPic;
ImageOptions mImageOptions;
private String mPicPath="http://pic33.nipic.com/20130916/3420027_192919547000_2.jpg";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
x.view().inject(this);
mImageOptions=new ImageOptions.Builder()
.setSize(DensityUtil.dip2px(100),DensityUtil.dip2px(100))//设置图片大小
.setRadius(DensityUtil.dip2px(5))//圆角半径
.setCrop(true)//是否对图片进行裁剪,如果ImageView的大小不是定义为wrap_content, 不要crop
.setFadeIn(true)//设置淡入效果
.setLoadingDrawableId(R.mipmap.ic_launcher)//设置加载过程中显示的图片
.setFailureDrawableId(R.mipmap.ic_launcher)//设置加载失败显示的图片
.setUseMemCache(true)//设置使用缓存
.setCircular(true)//设置图片显示为圆形
.setIgnoreGif(true)//设置支持gif
.build();
}
@Event(value=R.id.btn_start,type = View.OnClickListener.class)
private void startLoading(View v){
x.image().bind(mIvPic,mPicPath,mImageOptions);
}
...
运行效果图,如下所示,
PS:Callback.CommonCallback
new Callback.CommonCallback() {
@Override
public void onSuccess(Drawable result) {//获取成功
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {//获取失败
}
@Override
public void onCancelled(CancelledException cex) {//取消操作
}
@Override
public void onFinished() {//完成操作
}
}
图片加载其他方法的使用,请详看 xUtils的github上的sample以及源码。
五.DbUtils模块。
(1).android中的orm框架,一行代码就可以进行增删改查;
(2).支持事务,默认关闭;
(3).可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名);
(4).支持绑定外键,保存实体时外键关联实体自动保存或更新;
(5).自动加载外键关联实体,支持延时加载;
(6).支持链式表达查询,更直观的查询语义。
首先,我们需要定义数据库初始化配置数据,为了统一管理,数据库初始化配置可以放在一个单例类中或者自定义的Application中,需要添加如下代码,
...
private DbManager.DaoConfig daoConfig;
public DbManager.DaoConfig getDaoConfig() {
return daoConfig;
}
...
daoConfig = new DbManager.DaoConfig()
.setDbName("utils.db")//设置数据库的名称,默认是xutils.db
.setAllowTransaction(true)//设置是否允许事务,默认true
.setDbDir(new File("/sdcard")) // 设置数据库的存放路径, 默认存储在app的私有目录(数据库默认存储在/data/data/你的应用程序/database/xxx.db)
.setDbVersion(1)//设置数据库的版本号
//设置数据库打开的监听
.setDbOpenListener(new DbManager.DbOpenListener() {
@Override
public void onDbOpened(DbManager db) {
// 开启WAL, 对写入加速提升巨大
db.getDatabase().enableWriteAheadLogging();
}
})
//设置数据库更新的监听
.setDbUpgradeListener(new DbManager.DbUpgradeListener() {
@Override
public void onUpgrade(DbManager db, int oldVersion, int newVersion) {
// TODO: ...
// db.addColumn(...);
// db.dropTable(...);
// ...
// or
// db.dropDb();
}
});
...
此时,数据库还未创建!只有当我们执行以下代码,
DbManager db=x.getDb(new DaoConfig());
通过源码,我们可以得知,当数据库不存在时,就会创建数据库;如果数据库已经存在,则打开数据库。
private DbManagerImpl(DaoConfig config) {
if (config == null) {
throw new IllegalArgumentException("daoConfig may not be null");
}
this.daoConfig = config;
this.allowTransaction = config.isAllowTransaction();
this.database = openOrCreateDatabase(config);
DbOpenListener dbOpenListener = config.getDbOpenListener();
if (dbOpenListener != null) {
dbOpenListener.onDbOpened(this);
}
}
接着创建一个实体类,该实体类对应一张表,例如,
@Table(name = "tb_user")
public class Users {
@Column(name = "id", isId = true)
private int id;
@Column(name = "name")
private String name;
@Column(name = "age")
private int age;
@Column(name = "mobile")
private String mobile;
public Users() {
}
public Users(String name, int age, String mobile) {
setName(name);
setAge(age);
setMobile(mobile);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
@Override
public String toString() {
return "Users{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", mobile='" + mobile + '\'' +
'}';
}
}
使用注解来标注表名和列名,并且记得实体类要有无参的构造函数,以及实现get()、set()方法,否则可能会报错!
下面我们分别看看框架提供的CRUD方法。
1.新增数据。
/**
* 保存实体类或实体类的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;
例如新增数据,
DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
Users u=new Users();
u.setMobile("12345567890");
u.setAge(9);
u.setName("zhangsan");
try {
db.save(u);//创建表,并把数据存入
} catch (DbException e) {
e.printStackTrace();
}
运行截图如下所示,
如果想要显示表中的字段名,可以输入命令,‘.header on’,
DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
Users u1=new Users();
u1.setMobile("12");
u1.setAge(12);
u1.setName("li");
Users u2 = new Users();
u2.setMobile("13");
u2.setAge(13);
u2.setName("wang");
List userList= new ArrayList<>();
userList.add(u1);
userList.add(u2);
try {
db.save(userList);
} catch (DbException e) {
e.printStackTrace();
}
运行效果图如下所示,
2.查询操作。
查询数据
T findById(Class entityType, Object idValue) throws DbException;
T findFirst(Class entityType) throws DbException;
List findAll(Class entityType) throws DbException;
Selector selector(Class entityType) throws DbException;
DbModel findDbModelFirst(SqlInfo sqlInfo) throws DbException;
List findDbModelAll(SqlInfo sqlInfo) throws DbException;
(1).findById(Class通过主键从表中查找数据
DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
try {
Users u=db.findById(Users.class,2);
Log.e("Users",u.toString());
} catch (DbException e) {
e.printStackTrace();
}
运行截图如下所示,
(2).findFirst(Class
返回当前表中的第一条数据
DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
try {
Users u=db.findFirst(Users.class);
Log.e("Users",u.toString());
} catch (DbException e) {
e.printStackTrace();
}
运行截图如下所示,
返回当前表中的所有数据
DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
List list= null;
try {
list = db.findAll(Users.class);
for (int i=0;i
运行截图如下所示,
(4).DbModel findDbModelFirst(SqlInfo sqlInfo)
PS:DbModel内部是HashMap,(键是列名,值是对应的数据)。
SqlInfo参数是sql查询语句。
根据查询条件返回第一条数据,并组装为DbModel。
DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
try {
DbModel dbModel=db.findDbModelFirst(new SqlInfo("select * from tb_user"));
LogUtil.i("name="+dbModel.getString("name")+",age"+dbModel.getString("age"));
} catch (DbException e) {
e.printStackTrace();
}
运行截图如下所示,
(5).List
根据查询条件返回数据,并组装为DbModel列表。
DbManager db = x.getDb(((MyApplication) getApplicationContext()).getDaoConfig());
try {
List dbModelAll = db.findDbModelAll(new SqlInfo("select * from tb_user"));
for (DbModel dbModel : dbModelAll) {
LogUtil.i("name=" + dbModel.getString("name") + ",age" + dbModel.getString("age"));
}
} catch (DbException e) {
e.printStackTrace();
}
运行截图如下所示,
(6).selector(Class
组装sql查询语句
DbManager db = x.getDb(((MyApplication) getApplicationContext()).getDaoConfig());
try {
List list= db.selector(Users.class).where("age", ">", "12").findAll();
for (Users u : list) {
LogUtil.i(u.toString());
}
} catch (DbException e) {
e.printStackTrace();
}
运行截图如下所示,
其他有关查询操作就不多说了,最基本的其实是sql的拼写了!
3.下面看看删除操作。
删除数据 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;
(1).deleteById(Class> entityType, Object idValue)
根据表的主键进行单条记录的删除
DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
try {
db.deleteById(Users.class,1);//参数一表示表对应的实体类,参数二表示记录主键
} catch (DbException e) {
e.printStackTrace();
}
运行前,数据表截图,有三条数据,
执行完,结果截图如下所示,
(2).delete(Object entity)的用法
根据实体bean对表里面的一条或多条数据进行删除
DbManager db = x.getDb(((MyApplication) getApplicationContext()).getDaoConfig());
try {
List list= db.selector(Users.class).where("age", ">", "12").findAll();
db.delete(list);
} catch (DbException e) {
e.printStackTrace();
}
执行完,结果截图如下所示,
(3).delete(Class> entityType)
删除表格里面的所有数据,但是注意:表还会存在,只是表中数据清空了
DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
try {
db.delete(Users.class);
} catch (DbException e) {
e.printStackTrace();
}
(4).delete(Class> entityType, WhereBuilder whereBuilder)
DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
try {
db.delete(Users.class, WhereBuilder.b("age",">","20"));
} catch (DbException e) {
e.printStackTrace();
}
(5).dropTable(Class> entityType)
DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
try {
db.dropTable(Users.class);
} catch (DbException e) {
e.printStackTrace();
}
(6).dropDb()
DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
try {
db.dropDb();
} catch (DbException e) {
e.printStackTrace();
}
4.更新数据
void update(Object entity, String... updateColumnNames) throws DbException;
int update(Class> entityType, WhereBuilder whereBuilder, KeyValue... nameValuePairs) throws DbException;
(1).update(Object entity, String... updateColumnNames)
根据修改条件修改相应的数据。参数一要修改的数据,参数二要修改的字段名。
DbManager db = x.getDb(((MyApplication) getApplicationContext()).getDaoConfig());
try {
Users u=db.selector(Users.class).where("age","=","30").findFirst();
u.setMobile("1234");
u.setName("zhangsan");
db.update(u,"mobile");
List list= db.selector(Users.class).findAll();
for (Users u1 : list) {
LogUtil.i(u1.toString());
}
} catch (DbException e) {
e.printStackTrace();
}
运行后截图,
(2).update(Class> entityType, WhereBuilder whereBuilder, KeyValue... nameValuePairs)
根据修改条件修改相应的数据。参数一要修改的数据对应实体类,参数二要修改值的字段名,参数三、四...是新值
DbManager db = x.getDb(((MyApplication) getApplicationContext()).getDaoConfig());
try {
db.update(Users.class,WhereBuilder.b().and("age","=","12"),new KeyValue("age",30));
List list= db.selector(Users.class).findAll();
for (Users u : list) {
LogUtil.i(u.toString());
}
} catch (DbException e) {
e.printStackTrace();
}
运行后截图,
有关更加详细的介绍,请参考这篇文章,XUtils3框架的基本使用方法(二)。
PS: addColumn(Class> entityType, String column)
/**
* 添加一列,
* 新的entityType中必须定义了这个列的属性.
*
* @param entityType
* @param column
* @throws DbException
*/
void addColumn(Class> entityType, String column)
例如,tb_user表新增一列‘sex’,首先需要在实体类中增加相应的属性,以及实现它的get()和set()方法,然后执行下面的代码,
DbManager db = x.getDb(((MyApplication) getApplicationContext()).getDaoConfig());
try {
db.addColumn(Users.class,"sex");
} catch (DbException e) {
e.printStackTrace();
}
运行后截图如下所示,
有关数据操作还有其他的方法,博文就不拓展了,望读者自行查阅。
由于篇幅原因,有关网络模块就放到下篇文章!有关网络部分,详情请看xUtils使用详解(二)。如果还想了解更多,可以去xUtils的github上看它们的sample。