下面开始自问自答环节
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下面,下面看文件生成在截图中,看不到的话也没有关系,不太重要
![](https://img.haomeiwen.com/i23405214/5284aa9b0de6a348.png)
到这里就结束了
什么?怎么会没有了,提到的mvvm,databinding,viewModel,room这些呢?
这些都在源代码里面:需要的伙伴自己下载看看运行一下
github墙高了,就放gitee里面了
网友评论