cupboard2,rxcupboard2的使用

cupboard2,rxcupboard2的使用

前言:

最近在开发一个应用的时候,需要下载大量的基础数据。这时候便需要我们的sqlite出马了。于是就找到了一款轻量级的sqlite管理三方库cupboard2,这也是我的师兄安利给我的,用起来感觉还不错。在使用过程中也遇到过很多坑,一方面记录一下自己的解决问题的过程,另一方面希望同样遇到过这些问题的同学能快速脱坑。

使用:

首先在Gradle中引入库,这里我还使用了另一个库rxcupboard2,因为现在一般在项目中都会使用RxJava嘛,所以配合rxcupboard2使用效果更佳!

implementation 'nl.2312:rxcupboard2:2.0'

如果想单独使用cupboard2的可以看原作者,链接在这里:https://bitbucket.org/littlerobots/cupboard

然后创建你的SQLiteOpenHelper类,Cupboard将java类与数据库的表映射在一起,同时java类中的属性对应数据库表的列字段。如果数据库增加了表,修改了字段,总之任何数据库的变动,只需增加数据库版本cupboard会自动处理升级的问题。

`


import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import nl.qbusict.cupboard.Cupboard;

import static nl.qbusict.cupboard.CupboardFactory.cupboard;

public class CupboardDbHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "RxCupboard.db";
    private static final int DATABASE_VERSION = 1;

    private static SQLiteDatabase database;

    static {
        Cupboard cupboard = cupboard();
        cupboard.register(User.class);
    }


    public synchronized static SQLiteDatabase getConnection(Context context) {
        if (database == null) {
            // Construct the single helper and open the unique(!) db connection for the app
            database = new CupboardDbHelper(context.getApplicationContext()).getWritableDatabase();
        }
        return database;
    }

    public CupboardDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        cupboard().withDatabase(db).createTables();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        cupboard().withDatabase(db).upgradeTables();
    }
}
public class User {
    private long _id;
    private String userName;
    private String passWord;

    public long get_id() {
        return _id;
    }

    public void set_id(long _id) {
        this._id = _id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }
}
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    RxDatabase mDataBase = RxCupboard.withDefault(CupboardDbHelper.getConnection(this));
}

`

这里定义好你的实体类,并且在CupboardDbHelper类中的静态代码块儿中注册你的实体。运行起来就能看到你的数据库和你的表了。这里值得注意的是,_id 这个字段不管你写不写,Cupboard都会帮你创建一个 _id的字段并且他是主键自增的,翻看源码你可以发现。所以,我建议你还是在每张表里加上 _id这个字段。

`

boolean createNewTable(CupboardDatabase db, String table, List<Column> cols) {
    StringBuilder sql = new StringBuilder("create table '").append(table).append("' (_id integer primary key autoincrement");
...
}

`

代码确实非常简洁,简单的就创建好了你的sqlite和表。到这里差不多就可以愉快的使用的你数据库了。mDataBase.query(User.class);mDataBase.delete();mDataBase.put();等方法足够你的增删改查的使用,它还可以自定义查询删除等条件,这里就不赘述了。

然鹅。

当遇到较为复杂的查询的时候,总会拼写sql语句吧,你难免写下一些列名的硬编码。某一天,如果你的列名变了,类型也变了。这时候需要去查找用到这个列名的地方,并且一一修改,万一某个地方没改到。。。唉,不说了,毕竟被坑过。

cupboard提供了@Column,@Ignore注解,@Column代表给该列指定别称,@Ignore 表示忽略此字段不在数据库中创建该字段。或许是因为网上某些信息的误导,我确实使用了这俩注解,但发现并没有效果。别称和忽略似乎都没有生效。非常苦恼的去翻看了一下源码

/** * Annotation interface that allows one to decouple a field name from a column * name, by specifying the column name in an Annotation. This is particularly * useful when working with existing data like the {@link ContactsContract} ContentProvider as it utilises * generic column names (e.g. data1, data2,...,data15) which map to various * aliases depending on the mime type in use for a given row. * <p/> * Note that annotations are not processed by default. To enable processing of annotations construct an instance of Cupboard using {@link nl.qbusict.cupboard.CupboardBuilder} and call {@link nl.qbusict.cupboard.CupboardBuilder#useAnnotations()} <br/> */

@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.FIELD)
public @interface Column {
    String value();
}

虽然看不太懂这里注释的意思,但是大概意思是不能使用工厂产生的默认单例,需要开启某个设置。网上那个cupboard的文章,我估计他根本没试过这俩注解,唉,害苦我了。带着半猜测的态度,试着将CupboardDbHelper改写了一下。

`

public static final Cupboard cupboard;

static {
    cupboard = new CupboardBuilder().useAnnotations().build();
    cupboard.register(User.class);
}
public class User {

    public static final String USER_USERNAME = "name";
    public static final String USER_PASSWORD = "pwd";

    public long _id;
    @Column(USER_USERNAME)
    public String userName;
    @Column(USER_PASSWORD)
    public String passWord;
    @Ignore
    public String age;

}

`

运行之后发现,果然达到了我想要的效果。再也不用担心列名硬编码问题了。我很庆幸自己亲手去翻看了一下源码,没有继续执着看网上的教程。

然鹅。。。

当我愉快的往数据库里插入数据的时候,突然弹出了异常。。

java.lang.IllegalArgumentException: Entity is not registered: class User

这里写图片描述

f**k,居然提示我表没有注册? 我反复删除APP 测试,发现表确实已经创建了,但是就是不能插入数据。。思索良久,我便猜想会不会跟我改了cupboard创建方式有关,后来发现确实是。当我使用自己的创建的cupboard建表时,增删改操作确还是使用的工厂创建的默认实例。我忽略了这个问题。

`

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    RxDatabase mDataBase = RxCupboard.with(CupboardDbHelper.cupboard, CupboardDbHelper.getConnection(this));
    User user = new User();
    user.userName = "admin";
    user.passWord = "111111";
    mDataBase.put(user).subscribe();
}

`

运行后,数据成功插入数据库。

最后,当我觉得坑都排得差不多的时候。发现服务器返回的数据量比较多(好几千条),如果按照目前这种方式逐条插入的话,肯定会带来性能问题。因为sqlite是默认开启事务的,每次插入数据都会开启 提交 关闭事务。查看了一下Rxcupboard的源码, 发现他并没有批量插入的操作。cupboard倒是提供了批量插入的操作。

`

cupboard源码:

/**
 * Put multiple entities in a single transaction.
 *
 * @param entities the entities
 */
public void put(Collection<?> entities) {
    boolean mNestedTransaction = mDatabase.inTransaction();
    mDatabase.beginTransaction();
    try {
        for (Object entity : entities) {
            put(entity);
            if (!mNestedTransaction) {
                mDatabase.yieldIfContendedSafely();
            }
        }
        mDatabase.setTransactionSuccessful();
    } finally {
        mDatabase.endTransaction();
    }
}

`

好吧, 没有办法了,都到这个地步了,总不能弃坑吧。本着开源的精神,我便把Rxcupboard的源码下了下来,并稍微修改了一下。既然你不提供批量插入的操作,我就改成我想要的。于是便在RxDatabase中增加了一个方法

`

public <T> Single<Collection<T>> put(final Collection<T> entities) {
    return Single.fromCallable(new Callable<Collection<T>>() {
        @Override
        public Collection<T> call() throws Exception {
            dc.put(entities);
            return entities;
        }
    });
}

`

这就很舒服。。总算达到我理想的状态了,差不多小纠结了一天时间。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值