本内容主要介绍 Android 中使用 Room 保存数据到本地数据库的方法。

 以下是 Android Room 的官方介绍文档:

Room Persistence Library
(Room 库的简单介绍) https://developer.android.com/topic/libraries/architecture/room
Save data in a local database using Room
(Room 的使用指南) https://developer.android.com/training/data-storage/room/
Android Room with a View - Java
(Room 的使用实例) https://codelabs.developers.google.com/codelabs/android-room-with-a-view/#0

一、简介
  Room 是一个对象关系映射(ORM)库。可以很容易将 SQLite 表数据转换为 Java 对象。Room 在编译时检查 SQLite 语句。

  Room 为 SQLite 提供一个抽象层,以便在充分利用 SQLite 的同时,可以流畅地进行数据库访问。

1.1 添加依赖

在build.gradle 添加依赖

dependencies {

    def room_version = "2.2.0-beta01"

    implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" }

然后再在build.gradle 添加如下,不然build不过:

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

1.2 Room 组件
  Room 有 3 个主要的组件:

Database:包含数据库持有者,并作为与 App 持久关联数据的底层连接的主要访问点。

用 @Database 注解的类应满足以下条件:

是一个继承至 RoomDatabase 的抽象类。
在注解中包含与数据库相关联的实体列表。
包含一个具有 0 个参数的抽象方法,并返回用 @Dao 注解的类。
在运行时,您可以通过调用 Room.databaseBuilder() 或 Room.inMemoryDatabaseBuilder() 获取 Database 实例。

Entity:表示数据库内的表(Table)。

DAO:包含用于访问数据库的方法。

1.3 Room 各组件间关系
  Room 的大致使用方法如下:

App 通过 Room 的 Database 获取与数据库相关的数据库访问对象(DAO)。
然后,App 使用 DAO 从数据库中获取 Entity,并且将 Entity 的变化保存到数据库中。
最后,APP 使用 Entity 获取和设置数据库中表的数据。
  Room 中各组件之间的关系如图-1 所示:

二、Entity(实体)
  在使用 Room 持久化库(Room persistence library)时,需要将相关字段集定义为 Entity。对于每一个 Entity,在与其相关的 Database 对象中会创建一个表(Table)。

必须通过 Database 类的 entities 数组引用这个 Entity 类。

  下面的代码片段展示如何定义 Entity:

package com.example.jetpackdemo;

import androidx.room.Entity;
import androidx.room.PrimaryKey; @Entity
public class Word { @PrimaryKey(autoGenerate = true)
private Integer id; private String word; private String chinese; public Word(String word, String chinese) {
this.word = word;
this.chinese = chinese;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getWord() {
return word;
} public void setWord(String word) {
this.word = word;
} public String getChinese() {
return chinese;
} public void setChinese(String chinese) {
this.chinese = chinese;
} @Override
public String toString() {
return "Word{" +
"id=" + id +
", word='" + word + '\'' +
", chinese='" + chinese + '\'' +
'}';
}
}

法。在提供 getter 和 setter 方法时,需要遵守 Room 中的 JavaBeans 协议。

2.1 设置 Table 名称
  Room 默认使用类名作为数据库的 Table 名称。可以通过 @Entity 的 tableName 属性设置 Table 的名称。

(注意:在 SQLite 中,Table 名称是不区分大小写的。)

@Entity(tableName = "word")
public class Word { }

三、DAO(Data access object)
  在 Room 持久化库中,使用数据访问对象(data access objects, DAOs)访问 App 的数据。Dao 对象集合是 Room 的主要组件,因为每个 DAO 提供访问 App 的数据库的抽象方法。

  通过使用 DAO 访问数据库,而不是通过查询构造器或直接查询,可以分离数据库架构的不同组件。此外,在测试应用时,DAOs 可以轻松模拟数据库访问。

  DAO 可以是接口(interface),也可以是抽象类(abstract class)。如果是一个抽象类,可以有一个构造函数,其只接收一个 RoomDatabase 参数。在编译时,Room 为每个 DAO 创建具体实现。

package com.example.jetpackdemo;

import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update; import java.util.List; @Dao
public interface WordDao { @Insert
void insert(Word...words); @Update
void update(Word... words); @Query("delete from word")
void deleteAll(); @Query("select * from word")
List<Word> findAll(); }

注意:除非在构造器上调用 allowMainThreadQueries(),否则 Room 不支持在主线程上进行数据库访问,因为它可能会长时间锁定 UI。不过异步查询(返回 LiveData 或 Flowable 实例的查询)不受此规则约束,因为它们在需要时会在后台线程进行异步查询。

3.4.2 带参数的查询

  大多数情况下,需要将参数传递到查询中以执行筛选操作,例如仅需要显示大于某一年龄的 User。这时,我们可以使用方法参数。

@Dao
public interface MyDao {
@Query("SELECT * FROM user WHERE age > :minAge")
public User[] loadAllUsersOlderThan(int minAge);
}

在编译时,Room 使用 minAge 方法参数匹配 :minAge 绑定参数。如果存在匹配错误,将出现编译错误。

  还可以在查询中传递多个参数或者多次引用它们。

@Dao
public interface MyDao {
@Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
public User[] loadAllUsersBetweenAges(int minAge, int maxAge); @Query("SELECT * FROM user WHERE first_name LIKE :search " +
"OR last_name LIKE :search")
public List<User> findUserWithName(String search);
}

四、Database

  在 Room 持久化库中,通过 @Database 类访问数据库。

4.1 定义 Database

  下面的代码片段展示如何定义 Database:

package com.example.jetpackdemo;

import androidx.room.Database;
import androidx.room.RoomDatabase; @Database(entities = {Word.class},version = 1, exportSchema = false)
public abstract class WordDatabase extends RoomDatabase {
public abstract WordDao getWordDao();
}

五、测试案例

创建一个RoomActivity

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".RoomActivity"> <ScrollView
android:id="@+id/scrollView2"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@+id/guideline2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</ScrollView> <androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.6" /> <Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="@string/btn5"
app:layout_constraintBottom_toTopOf="@+id/guideline3"
app:layout_constraintEnd_toStartOf="@+id/guideline4"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline3" /> <Button
android:id="@+id/button6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="@string/btn6"
app:layout_constraintBottom_toTopOf="@+id/guideline3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline4"
app:layout_constraintTop_toTopOf="@+id/guideline3" /> <androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.75" /> <androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" /> <androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.875513" /> <Button
android:id="@+id/button7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/btn8"
app:layout_constraintBottom_toTopOf="@+id/guideline5"
app:layout_constraintEnd_toStartOf="@+id/guideline4"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline5" /> <Button
android:id="@+id/button8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="@string/btn9"
app:layout_constraintBottom_toTopOf="@+id/guideline5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline4"
app:layout_constraintTop_toTopOf="@+id/guideline5" /> <TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="@+id/scrollView2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.example.jetpackdemo;

import androidx.appcompat.app.AppCompatActivity;
import androidx.room.Insert;
import androidx.room.Room; import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView; import java.util.List; public class RoomActivity extends AppCompatActivity { private WordDatabase wordDatabase;
private WordDao wordDao;
private Button btn5,btn6,btn7,btn8;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_room); wordDatabase = Room.databaseBuilder(this,WordDatabase.class,"word_database").allowMainThreadQueries().build();
wordDao = wordDatabase.getWordDao();
btn5 = findViewById(R.id.button5);
btn6 = findViewById(R.id.button6);
btn7 = findViewById(R.id.button7);
btn8 = findViewById(R.id.button8); tv = findViewById(R.id.textView); btn5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Word word1 = new Word("hello","你好");
Word word2 = new Word("world","世界"); wordDao.insert(word1,word2);
show();
}
}); btn6.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
show();
}
}); btn7.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Word word = new Word("hi","你好");
word.setId(5);
wordDao.update(word);
show();
}
}); btn8.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
wordDao.deleteAll();
show();
}
}); } private void show()
{
List<Word> list = wordDao.findAll();
StringBuilder sb =new StringBuilder();
for (Word w : list){
sb.append(w.toString()+"\n");
}
tv.setText(sb.toString());
} }

 六、效果:

Android Room 使用案例的更多相关文章

  1. Android实训案例(九)——答题系统的思绪,自己设计一个题库的体验,一个思路清晰的答题软件制作过程

    Android实训案例(九)--答题系统的思绪,自己设计一个题库的体验,一个思路清晰的答题软件制作过程 项目也是偷师的,决心研究一下数据库.所以写的还是很详细的,各位看官,耐着性子看完,实现结果不重要 ...

  2. Android实训案例(八)——单机五子棋游戏,自定义棋盘,线条,棋子,游戏逻辑,游戏状态存储,再来一局

    Android实训案例(八)--单机五子棋游戏,自定义棋盘,线条,棋子,游戏逻辑,游戏状态存储,再来一局 阿法狗让围棋突然就被热议了,鸿洋大神也顺势出了篇五子棋单机游戏的视频,我看到了就像膜拜膜拜,就 ...

  3. Android实训案例(六)——四大组件之一BroadcastReceiver的基本使用,拨号,短信,SD卡,开机,应用安装卸载监听

    Android实训案例(六)--四大组件之一BroadcastReceiver的基本使用,拨号,短信,SD卡,开机,应用安装卸载监听 Android中四大组件的使用时重中之重,我这个阶段也不奢望能把他 ...

  4. Android实训案例(五)——四大组件之一ContentProvider的使用,通讯录的实现以及ListView的优化

    Android实训案例(五)--四大组件之一ContentProvider的使用,通讯录的实现 Android四大组件是啥这里就不用多说了,看图吧,他们之间通过intent通讯 我们后续也会一一的为大 ...

  5. Android实训案例(四)——关于Game,2048方块的设计,逻辑,实现,编写,加上色彩,分数等深度剖析开发过程!

    Android实训案例(四)--关于Game,2048方块的设计,逻辑,实现,编写,加上色彩,分数等深度剖析开发过程! 关于2048,我看到很多大神,比如医生,郭神,所以我也研究了一段时间,还好是研究 ...

  6. Android实训案例(三)——实现时间轴效果的ListView,加入本地存储,实现恋爱日记的效果!

    Android实训案例(三)--实现时间轴效果的ListView,加入本地存储,实现恋爱日记的效果! 感叹离春节将至,也同时感叹时间不等人,一年又一年,可是我依然是android道路上的小菜鸟,这篇讲 ...

  7. Android实训案例(二)——Android下的CMD命令之关机重启以及重启recovery

    Android实训案例(二)--Android下的CMD命令之关机重启以及重启recovery Android刚兴起的时候,着实让一些小众软件火了一把,切水果,Tom猫,吹裙子就是其中的代表,当然还有 ...

  8. Android实训案例(一)——计算器的运算逻辑

    Android实训案例(一)--计算器的运算逻辑 应一个朋友的邀请,叫我写一个计算器,开始觉得,就一个计算器嘛,很简单的,但是写着写着发现自己写出来的逻辑真不严谨,于是搜索了一下,看到mk(没有打广告 ...

  9. android 性能分析案例

    本章以实际案例分析在android开发中,性能方面的优化和处理.设计到知识点有弱引用,memory monitor,Allocation Tracker和leakcanary插件. 1.测试demo ...

  10. Android Studio精彩案例(六)《使用一个Demo涵盖补间动画所有知识》

    转载本专栏文章,请注明出处,尊重原创 .文章博客地址:道龙的博客 元旦假期里,闲的无事,看到美团加载数据的动画,就突想写个Demo把动画知识集成一下.后来想了想,还是直接用一个Demo来把所有动画知识 ...

随机推荐

  1. 自动化远程部署shell脚本

    历史原因,有一段时间,项目开发采用一种模式:项目开发及代码版本管理在外网,而主要测试在内网.所以为了同步开发进度,每天会将所有服务在外网jenkins上打包好,然后将服务jar包拷进内网,由于内网服务 ...

  2. 自定义Spring Boot内置tomcat的404页面

    spring boot 的相关404页面配置都是针对项目路径下的(如果配置了 context-path) 在context-path不为空的情况下,如果访问路径不带context-path,这时候会显 ...

  3. checkbox与label内的文字垂直居中的解决方案

    <label style="float:left;margin-top:5px;margin-left:10px;cursor:pointer"><input t ...

  4. AudioManager: android插上耳机仍然使用扬声器播放音频

    手机音频的输出有外放(Speaker).听筒(Telephone Receiver).有线耳机(WiredHeadset).蓝牙音箱(Bluetooth A2DP)等输出设备.在平时,电话免提.插拔耳 ...

  5. Xamarin图表开发基础教程(3)OxyPlot框架

    Xamarin图表开发基础教程(3)OxyPlot框架 Xamarin.Android中使用OxyPlot框架 在Xamarin.Android平台上实现图表显示需要完成以下的步骤: 1.添加OxyP ...

  6. AIX 系统参数配置

    AIX 系统参数配置 原创 Linux操作系统 作者:fanhongjie 时间:2008-05-08 22:46:37 540 0 AIX内核属于动态内核,核心参数基本上可以自动调整,因此当系统安装 ...

  7. 【NumPy】 之常见运算(np.around、np.floor、np.ceil、np.where)

    aroundnp.around 返回四舍五入后的值,可指定精度. around(a, decimals=0, out=None) a 输入数组 decimals 要舍入的小数位数. 默认值为0. 如果 ...

  8. odoo开发笔记 -- 多个子类继承同一个父类方法的执行顺序

    场景描述: odoo模块化开发的架构理念,科学&高效, 可以让很多业务场景,尽可能松耦合:让开发人员的主要精力,关注在当前的业务逻辑: 所谓「前人栽树,后人乘凉」,模块整体好比一棵大树, 开发 ...

  9. vue---监听浏览器窗口的宽度

    使用VUE开发后台项目,后台项目需要进行后台根据浏览器窗口进行变化,需要使用vue来监听浏览器的窗口变化. <template>     <div class="conte ...

  10. MD5(2)

    /************************************************ MD5 算法的Java Bean @author:Topcat Tuppin Last Modifi ...