最近出现了一个bug,room报错为“disk I/O error (code 522)”导致room用不了,第一次还是好好地,然后就不行了。我就学了和写了一个room的demo版本。
废话不多说,找到一个jetback demo很好的资源,分享给大家。
一、jetback是什么
2018年谷歌I/O 发布了一系列辅助android开发者的实用工具,合称Jetpack,以帮助开发者构建出色的 Android 应用。
Android Jetpack 附带五个新组件:
- WorkManager alpha 版
- 导航 alpha 版
- 分页稳定版
- 切片 alpha 版
- Android KTX(Kotlin 扩展程序)alpha 版
分页稳定版:它可以从本地存储和/或网络加载分页数据,并让您能够定义内容的加载方式。此组件原生支持 Room、LiveData 和 RxJava。
其他具体这里就不详细说明了,大家可以参考:Android Jetpack简介
二、Room简介
2.1 Room是什么
Room是Google提供的一个ORM库。Room提供了三个主要的组件:
- @Database:@Database用来注解类,并且注解的类必须是继承自RoomDatabase的抽象类。该类主要作用是创建数据库和创建Daos(data access objects,数据访问对象)。
- @Entity:@Entity用来注解实体类,@Database通过entities属性引用被@Entity注解的类,并利用该类的所有字段作为表的列名来创建表。
- @Dao:@Dao用来注解一个接口或者抽象方法,该类的作用是提供访问数据库的方法。在使用@Database注解的类中必须定一个不带参数的方法,这个方法返回使用@Dao注解的类
2.2 Room架构图如下
三、实例
3.1 代码结构图
3.2 用到的Library文件
//jetpack room androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation 'android.arch.persistence.room:runtime:1.1.1' annotationProcessor 'android.arch.persistence.room:compiler:1.1.1'
3.3 User.java文件
// 定义User表, 用Entity注解来表示这个类是一个数据库表
@Entity(tableName = "users")
public class User {
@PrimaryKey(autoGenerate = true)
public int uid;
@ColumnInfo(name = "user_name")
public String name = "";
@ColumnInfo(name = "user_age")
public int age = 0;
@Override
public String toString() {
return "{User, uid : $uid ,name : $name ,age :$age}";
}
}
3.4 IUserDao.java---IUserDao接口
// 定义数据访问对象的接口
@Dao
public interface IUserDao {
@Insert
void insertAll(User... users);//支持可变参数
@Delete
void delete(User user);
@Delete
void deleteAll(List<User> users);
@Query("SELECT * FROM users")
List<User> getAllUsers();
@Query("SELECT * FROM users WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);//根据uid查询
@Update
void updateUser(User user);
}
3.5 AppDatabase.java---database对象类
/**
* Room框架的database对象类,应该使用单例模式
* Author: .tangwuke
* Date: 2019/09/02
*/
@Database(entities = {User.class}, version = 1,exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
public static final String DB_NAME = "user.db";
private static AppDatabase instance;
public static synchronized AppDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(context, AppDatabase.class, DB_NAME)
.allowMainThreadQueries()//默认room不允许在主线程操作数据库,这里设置允许
.build();
}
return instance;
}
public abstract IUserDao getUserDao();
}
3.6 MainActivity.java---使用类
public class MainActivity extends AppCompatActivity {
private static final String TAG = "tangtang";
IUserDao userDao = null;
private AppDatabase instance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
deleteUser(-1);
addUser("用户A",15);
addUser("用户B",16);
addUser("用户C",17);
queryAll();
updateUser(1,"用户A被改名了");
queryAll();
deleteUser(2);
queryAll();
}
public void init(){
Log.d(TAG, "init: This is init");
userDao = AppDatabase.getInstance(this.getApplication()).getUserDao();
}
// 增加用户
public void addUser(String name, int age){
User user = new User();
user.name = name;
user.age = age;
Log.d(TAG, "addUser: " + user.name+" "+user.age);
userDao.insertAll(user);
}
//删除指定id 用户
public void deleteUser(int uid){
User user = new User();
user.uid = uid;
Log.d(TAG, "deleteUser: " + user.uid);
userDao.delete(user);
if(uid == -1){
List<User> users = userDao.getAllUsers();
userDao.deleteAll(users);
}
}
//更新某指定id 用户
public void updateUser(int uid,String strName){
User user = new User();
user.uid = uid;
user.name = strName;
userDao.updateUser(user);
}
//查找全部用户
public void queryAll() {
List<User> users = userDao.getAllUsers();
for (User oneUser : users){
Log.d(TAG, "queryAll: name:" + oneUser.name+" age: "+oneUser.age+" uid: "+oneUser.uid);
}
}
}
以上就是所有的源码分布,有不知道或者不清楚的欢迎再公众号来留言交流。
四、报错原因
4.1 原因分析
写完demo测试是没有问题的。然后回看问题代码,研究发现在room 创建数据对象的方法中databaseBuilder修改个database名称就没有问题了。
当然这不是问题的根源,问题的根源是,这个库在jni中使用sqlite3_open地方打开,然后导致冲突报错。
4.2 Room中打开
4.3 sqlite3中打开
4.4 尝试解决
将打开方式由sqlite3_open改成sqlite3_open_v2中使用SQLITE_OPEN_READONLY(只读模式)打开
结果还是报错。这个问题暂时我没有什么好方法,就留给大家。大家有好方法记得给我留言或者去我们公众号分享给我,谢谢!
结束语
以上就是本次分享的Room写法以及disk I/O error (code 522)错误原因。最后惯例给大家推介一下我们的技术工作号,欢迎大家来交流技术问题,谢谢!