我对(jetpack)room的使用心得

下面开始自问自答环节

1.为什么写这篇文章?

答:尽管room的文章很多,但是我找了半天发现几乎都是不够全面或者说不明白,又或者看了让人不敢引用到项目中去。

2.这篇文章有什么内容,值不值得你去阅读?

主:room的增,删,改,查,存储复杂数据(很多文章根本不提)
次:一个人思路清晰的基本框架(mvvm)、一个基本的登陆功能(loginActivity)
涉及技术点:databinding,viewModel,room

文章对应的项目链接在文章末尾

开始我对room的使用心得

1.先导入room(2.4.3是目前最新的稳定版本,版本之间区别有点大,用法也不太一样)

 def room_version = "2.4.3"
    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version"

2.注意看User是如何变成一个user_table

@Entity(tableName = "user_table")
@TypeConverters(value = {
        TestBean2Converter.class,
        UserWorkConverter.class,
        UserWorkListConverter.class
})
public class User {
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "user_id", typeAffinity = ColumnInfo.INTEGER)
    private int id;
    @ColumnInfo(typeAffinity = ColumnInfo.TEXT)
    private String userId;//一般后台都有一个userId唯一值
    @ColumnInfo(typeAffinity = ColumnInfo.TEXT)
    private String name;
    @ColumnInfo(typeAffinity = ColumnInfo.TEXT)
    private String pwd;
    @ColumnInfo(typeAffinity = ColumnInfo.TEXT)
    private String loginTime;
    @Ignore//不被持久化的数据
    private String a;
    //测试list对象
    private List<UserWork> list;
    //测试单个对象
    private UserWork userWork;
    //测试两个对象会发生什么?
    private TestBean2 testBean2;
    //省略get/set
}

@ Entity:标注为一个表,可以通过tableName定义表名

@ PrimaryKey:标注这个属性作为主键,autoGenerate表示自增长(这些基础学过sql的都应该知道)

@ ColumnInfo:标注在属性上,可以通过name定义表中的名字,typeAffinity标注属性在表中的类型(具体可以查看ColumnInfo中的常量)

@ Ignore:可以用在构造或者属性上,用在属性上表示这个属性不会被持久化,用构造上则让room忽略这个构造方法,因为在room中,一个类只认识一个构造方法,其他的则用这个注解标注。

@ TypeConverters:这个注解的内容是一个class数组,用于转换数据的作用,因为room提供了常规类型的支持,如果是自定义的对象或者list对象则需要通过转换器(可以看到对list,userWork,testBean2这几个特殊类型属性进行转换的)

注意:UserWork和Testbean2只是一个普通的类,并没有被@Entity标注,因为我个人觉得如果再次添加@Entity注解将大大增加使用的复杂性,日常开发中并不需要那么复杂的东西,尽管官方提供了支持

3.如何拿到一个database?

@Database(
        entities = {//实体表
                User.class
        },
        exportSchema = true,
        version = 1//当前版本号
//        autoMigrations = {//配置自动升级
//                @AutoMigration(from = 1,to = 2,spec = USerSpec.class)
//        }
)
public abstract class AppDataBase extends RoomDatabase {

    private static final String DB_NAME = "blackbox_db";

    public abstract IUserDao getUserDao();

    public static AppDataBase getInstance() {
        return Helper.INSTANCE;
    }

    private final static class Helper {

        private static final AppDataBase INSTANCE = Room.databaseBuilder(Utils.getApp(), AppDataBase.class, DB_NAME)
//                .addMigrations()//迁移
                .allowMainThreadQueries()//禁止主线程操作
                .addCallback(new Callback() {
                    @Override
                    public void onCreate(@NonNull SupportSQLiteDatabase db) {
                        super.onCreate(db);
                        LogUtils.iTag("room", "onCreate***");
                    }

                    @Override
                    public void onOpen(@NonNull SupportSQLiteDatabase db) {
                        super.onOpen(db);
                        LogUtils.iTag("room", "onOpen***");
                    }
                })
                .build();

    }
}

@Database:标注这个类为dataBase类型,可以看到有很多属性,比如:
(1)entities里面放到的是(数组)表的类名,
(2)version是当前数据库的版本,
(3)autoMigrations:这个非常有意思,可以配置数据库自动迁移(有很多细节需要处理)

Helper这个类没什么可说的自己看看就行,需要注意的是room这类提供了很多方法,需要的自己看看就行,需要注意的是addMigrations在以望的版本中如果不支持自动升级,则需要手动写迁移代码

细心的小伙伴应该注意到了getUserDao方法,这个是关键

5.配置数据库升级的小细节

/***
 * 修改表名 和字段名
 */
@RenameTable(fromTableName = "user_table", toTableName = "user_table1")
@RenameColumn(tableName = "user_table1", fromColumnName = "name", toColumnName = "name1")
public class USerSpec implements AutoMigrationSpec {
}

虽然自动迁移看起来很牛,但是不够智能,需要告诉room,你做了什么改动,比如修改类名和表的字段名
@ RenameTable:修改表名
@ RenameColumn:修改哪个表的字段名
注意:这个类需要加到@Database的autoMigrations的某个版本升级中的spec中

6.下面是room的增,删,改,查环节

@Dao()
public interface IUserDao {

    @Query("SELECT * FROM user_table")
    List<User> getAll();


    @Delete(entity = User.class)
    int deleteUser(User user);

    @Query("SELECT * FROM user_table WHERE userId=:userId")
    User queryByUserId(String userId);

    //存在则替换
    @Insert(entity = User.class, onConflict = OnConflictStrategy.REPLACE)
    void insertUser(User... user);

    @Update(entity = User.class)
    void update(User user);
}

@ Dao:标注为数据库操作类
@Query:查询,需要写查询语句
@Insert:不需要语句,onConflict是策略,可以看看
@ Delete:删除,不需要sql语句
@ Update:修改,不需要sql语句

可以看到除了@query需要语句,其他的都可以不用,但是其他操作可以写sql去执行吗?是可以的,可以通过@query写其他的语句,但是支持性怎么样,我没有尝试

7.案例

public class MainViewModel extends AndroidViewModel {

    public ObservableField<String> log = new ObservableField<>("Log: \n");

    IUserDao userDao;

    public MainViewModel(@NonNull Application application) {
        super(application);
        userDao = AppDataBase.getInstance().getUserDao();
    }


    public void onSearchClick(View v) {
        ThreadUtils.getCachedPool().execute(() -> {
            List<User> list = userDao.getAll();
            StringBuffer buffer = new StringBuffer("log:\t共:" + list.size() + "+\n\n");
            for (User item : list) {
                buffer.append("\n\n").append(GsonUtils.toJson(item));
            }
            log.set(buffer.toString());
            LogUtils.iTag("roomQueryByUserId", buffer.toString());
        });

    }

    public void update(View v) {
        ThreadUtils.getCachedPool().execute(() -> {
            try {
                User user = userDao.queryByUserId("007");
                user.setA("AAAA");
                user.setName("cba");
                userDao.update(user);
            } catch (Throwable e) {
            }


        });
    }

    public void add(View v) {
        ThreadUtils.getCachedPool().execute(() -> {
            User user = new User();
            user.setUserId("007");
            user.setName("abc");
            user.setLoginTime("2022-10-10");
            userDao.insertUser(user);

        });
    }

    public void delete(View v) {
        ThreadUtils.getCachedPool().execute(() -> {
            try {
                User a007 = userDao.queryByUserId("007");
                userDao.deleteUser(a007);
            } catch (Throwable e) {
            }
        });
    }


}

上面的增删改查,已经全部通过测试,没有任何问题

8.最后补充一点细节,room升级配置生成文件

 //room
        javaCompileOptions {
            annotationProcessorOptions {
                arguments += [
                        "room.schemaLocation":"$projectDir/schemas".toString(),
                        "room.incremental":"true",
                        "room.expandProjection":"true"]
            }
        }

注意配置在defaultConfig下面,下面看文件生成在截图中,看不到的话也没有关系,不太重要

image.png

到这里就结束了

什么?怎么会没有了,提到的mvvm,databinding,viewModel,room这些呢?

这些都在源代码里面:需要的伙伴自己下载看看运行一下

room对应的demo仓库地址

github墙高了,就放gitee里面了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,820评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,648评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,324评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,714评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,724评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,328评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,897评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,804评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,345评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,431评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,561评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,238评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,928评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,417评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,528评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,983评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,573评论 2 359

推荐阅读更多精彩内容