Android Room DAO插入数据失败及数据库线程作用问题咨询
问题原因
- 核心错误是
User类缺少@Entity注解。Room框架要求所有映射为数据库表的实体类必须添加@Entity注解,你只在AppDatabase的entities参数中声明了User.class,但类本身没有加注解的话,Room无法识别该类为合法表结构,运行时会直接抛出异常进入catch块,自然不会打印成功日志,也无法完成数据插入。 - 额外的用法错误:你每次执行插入操作都重新调用
Room.databaseBuilder()构建新的数据库实例。Room数据库实例属于重量级对象,全局应该只初始化一次、复用同一个实例,重复构建不仅会造成不必要的性能开销,还可能触发数据库文件锁冲突,导致操作失败。 - 小瑕疵:DAO层
@Query("select*from User")的SQL语句语法不规范,select和*、*和from之间缺少空格,部分SQL解析场景下会执行失败,建议修正为@Query("SELECT * FROM User")。
修正代码参考
修正后的User类:
@Entity // 必须添加该注解,声明为Room实体类 public class User { @PrimaryKey @NonNull public String uid; @ColumnInfo(name = "name") public String name; public User(String uid, String name){ this.uid = uid; this.name = name; } }
数据库单例封装,避免重复创建实例:
public class AppDbManager { private static AppDatabase sInstance; public static AppDatabase getDatabase(Context context) { if (sInstance == null) { synchronized (AppDbManager.class) { if (sInstance == null) { sInstance = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "user_db") .build(); } } } return sInstance; } }
修正后的插入逻辑:
new Thread(new Runnable() { @Override public void run() { try { AppDatabase db = AppDbManager.getDatabase(activity.getApplicationContext()); UserDAO userDao = db.userDAO(); userDao.insertAll(new User("11", "Melany")); Log.d("main_activity_uid", "ok you are pretty"); } catch (Exception e) { e.printStackTrace(); } } }).start();
数据库操作使用子线程的作用
- Android主线程(UI线程)的核心职责是渲染界面、响应用户交互事件,系统要求主线程中不能执行耗时过长的操作,否则会触发界面掉帧卡顿,甚至弹出ANR(应用无响应)弹窗导致应用闪退。
- 数据库读写属于磁盘IO操作,执行时间受数据量、磁盘性能影响很大,耗时不可控,本身就属于严禁放在主线程执行的耗时操作。
- Room框架本身做了强制校验,默认情况下禁止在主线程调用任何数据库操作方法,违规调用会直接抛出异常。开子线程的核心作用就是把数据库IO逻辑从主线程剥离,既不阻塞UI渲染,也符合Room的线程使用规则。
内容的提问来源于stack exchange,提问作者Elly
相关产品推荐
相关产品推荐

