Room 持久库提供了一个 SQLite 抽象层,让你访问数据库更加稳健,提升数据库性能。
该库帮助您在运行应用程序的设备上创建应用程序的数据缓存。这个缓存是你的应用程序唯一的真实来源,允许用户查看应用程序中关键信息的一致副本,而不管用户是否有Internet连接。
使用 Room 需要添加依赖:
dependencies {
def room_version = "2.2.0-alpha01"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" // use kapt for Kotlin
// optional - RxJava support for Room
implementation "androidx.room:room-rxjava2:$room_version"
// optional - Guava support for Room, including Optional and ListenableFuture
implementation "androidx.room:room-guava:$room_version"
// Test helpers
testImplementation "androidx.room:room-testing:$room_version"
}
Room在SQLite上提供了一个抽象层,以便在发挥SQLite能力的同时允许流畅的数据库访问。
处理复杂的结构化数据的应用程序可以极大地受益于本地数据的持久化。最常见的用例是缓存相关的数据片段。这样,当设备无法访问网络时,用户仍然可以在离线时浏览该内容。在设备返回联机之后,任何用户发起的内容更改都会同步到服务器。
Room有3个主要的组件:
Database:包含数据库持有者,并充当与应用程序持久化的、关系型的数据的底层连接的主要访问点。
用@Database注解的类应满足以下条件:
是一个继承 RoomDatabase 的抽象类。
在注释中包含与数据库相关联的实体列表。
包含一个具有0个参数的抽象方法,并返回用@Dao注释的类。
在运行时,可以通过调用Room.databaseBuilder()或Room.inMemoryDatabaseBuilder()获取数据库实例。
Entity:表示数据库内的表。
DAO: 包含用于访问数据库的方法。
@Entity 这个注解是引用了 Room 库后出现的,相当于定义了数据库中的一张表(table)。
我们利用 @PrimaryKey(autoGenerate = true) 设置某个字段为主键,并且自动生长。
@ColumnInfo(name = “english_word”) 给字段设置别名,如果不设置就默认为变量名。
利用 idea 快速生成构造器(id 不需要作为参数,因为id是系统自动生成的)。
利用 idea 快速生成 get 与 set 方法(id 可以写,单没必要)。
建立一个 Word.java 文件,利用注解标记为 Entity,代码如下:
@Entity
public class Word { // 实体类
@PrimaryKey(autoGenerate = true) // 设置主键,并且自动生长
private int id;
@ColumnInfo(name = "english_word") // 设置别名,如果不设置就默认为变量名
private String word;
@ColumnInfo(name = "chinese_meaning")
private String chineseMeaning;
public Word(String word, String chineseMeaning) {
this.word = word;
this.chineseMeaning = chineseMeaning;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public String getChineseMeaning() {
return chineseMeaning;
}
public void setChineseMeaning(String chineseMeaning) {
this.chineseMeaning = chineseMeaning;
}
}
Dao 指的是 Database aceess object,即访问数据库操作的接口。我们所有的数据库的操作,都将在这里声明,如增删改查。利用注解功能可以很方便的执行操作。
@Insert 表示插入记录。
@Update 表示修改数据库中的记录。
@Delete 表示删除数据库中记录。
@Query(" ") 中可以写入SQL语句,来执行操作。
声明一个接口文件 WordDao.java,利用注解标记为 Dao,代码如下:
@Dao // Database aceess object 访问数据库操作的接口
public interface WordDao { // 在这里声明数据库的操作,如增删改查
@Insert
void insertWords(Word... word); // 可以传递三个参数
@Update
void updatWords(Word... words);
@Delete
void deleteWords(Word... words);
@Query("DELETE FROM WORD")
void deleteAllWords();
@Query("SELECT * FROM WORD ORDER BY ID DESC") // 降序排列
List<Word> getAllWords();
}
Database 文件必须要继承 androidx.room.RoomDatabase,并且得是抽象类。
@Database() 中必须指明 entities ,传入我们之前创建的 entity,这里是个集合,可以传入多个值。
version 作为版本号,当数据库结构发生改变时,数据库版本会增加,以后会配合 Migration 进行数据迁移。
建立一个 WordDatabases.java 文件,利用注解标记为 Database,代码如下:
@Database(entities = {Word.class}, version = 1, exportSchema = false)
public abstract class WordDatabase extends RoomDatabase {
public abstract WordDao getWordDao(); // 若有多个 Entity,则应该写多个 Dao
}
搭建如图界面:
来到 MainActiviry.xml 中,代码如下:
updateView() 是用来刷新界面的,每次对数据库进行操作后,要通过页面来显示效果。
值得注意的是,数据库不允许在主线程中执行,因为加载的资源如果,但是我们可以通过allowMainThreadQueries() 强制允许在主线程执行,在真实开发中不要这么做,这里只是为了演示效果。
Dao 模式与以前学习 JavaEE 时基本类似,所以很好理解。
public class MainActivity extends AppCompatActivity {
WordDatabase wordDatabase;
WordDao wordDao;
TextView textView;
Button buttonInsert,buttonUpdate,buttonDelete,buttonClear;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView2);
// allowMainThreadQueries() 强制允许在主线程执行,真实开发中不要这么做
wordDatabase = Room.databaseBuilder(this,WordDatabase.class,"word_database").allowMainThreadQueries().build();
wordDao = wordDatabase.getWordDao();
updateView();
buttonInsert = findViewById(R.id.buttonInsert);
buttonUpdate = findViewById(R.id.buttonUpdate);
buttonDelete = findViewById(R.id.buttonDelete);
buttonClear = findViewById(R.id.buttonClear);
buttonInsert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Word word1 = new Word("Hello","你好");
Word word2 = new Word("World","世界");
wordDao.insertWords(word1,word2);
updateView();
}
});
buttonClear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
wordDao.deleteAllWords();
updateView();
}
});
buttonUpdate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Word word = new Word("good","真棒");
word.setId(20);
wordDao.updatWords(word);
updateView();
}
});
buttonDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Word word = new Word("", "");
word.setId(20);
wordDao.deleteWords(word);
updateView();
}
});
}
void updateView(){
List<Word> list = wordDao.getAllWords();
String text = "";
for(int i = 0; i < list.size(); i++){
Word word = list.get(i);
text += word.getId() + ":" + word.getWord() + ":" + word.getChineseMeaning() + "\n";
}
textView.setText(text);
}
}
至于保存的数据库文件,可以在存储中找到,我们可以将数据库文件导出,然后利用一些工具例如 db Browser 来查看数据。