xUtils使用详解(一)

    一直都听闻有个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文件中添加网络权限,具体权限如下,

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

二、使用。

创建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,代码如下,

 <application
            android:name=".MyApplication"
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

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中是一样的,此处就不在细说。
下面给出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<Drawable>() {...});
x.image().loadDrawable(url, imageOptions, new Callback.CommonCallback<Drawable>() {...});
// 用来获取缓存文件
x.image().loadFile(url, imageOptions, new Callback.CommonCallback<File>() {...});
上面的方法中都有一个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<Drawable>  回调方法(这个地方使用它,更加灵活、方便地加载图片)

    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() {//完成操作

            }
        }
图片加载其他方法的使用,请详看 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’,


save()方法还支持传递一个列表,例如,

        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<Users> userList= new ArrayList<>();
        userList.add(u1);
        userList.add(u2);
        try {
            db.save(userList);
        } catch (DbException e) {
            e.printStackTrace();
        }
运行效果图如下所示,


其他方法就不一一列举了!

2.查询操作。

查询数据

    <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;

(1).findById(Class<T> entityType, Object idValue)

通过主键从表中查找数据

 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<T> entityType)

返回当前表中的第一条数据

        DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
        try {
            Users u=db.findFirst(Users.class);
            Log.e("Users",u.toString());
        } catch (DbException e) {
            e.printStackTrace();
        }
运行截图如下所示,


(3).findAll(Class<T> entityType)

返回当前表中的所有数据

        DbManager db=x.getDb(((MyApplication)getApplicationContext()).getDaoConfig());
        List<Users> list= null;
        try {
            list = db.findAll(Users.class);
            for (int i=0;i<list.size();i++){
                LogUtil.e("user"+list.get(i).toString());
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
运行截图如下所示,


(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> findDbModelAll(SqlInfo sqlInfo)

根据查询条件返回数据,并组装为DbModel列表。

      DbManager db = x.getDb(((MyApplication) getApplicationContext()).getDaoConfig());
        try {
            List<DbModel> 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<T> entityType)

组装sql查询语句

        DbManager db = x.getDb(((MyApplication) getApplicationContext()).getDaoConfig());
        try {
            List<Users>  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<Users>  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) 
根据where语句的条件进行删除操作        

        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<Users>  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<Users>  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。






  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值