Room来源
Android采用Sqlite作为数据库存储。由于Sqlite代码写起来繁琐且容易出错,因此,开源社区逐渐出现了各种ORM(Object Relational Mapping)库。常见的有ORMLite, GreenDAO等。Google也意识到推出自家ORM库的必要性,于是有了Room,Room同其他ORM库一样,也是在Sqlite上提供了一层封装。
Room 主要组件
Room
包含三个主要组件:- (1)(Entity)数据实体,用于表示应用的数据库中的表;
- (2)(Dao)数据访问对象 (Data Access Objects),提供您的应用可用于插入、删除、更新和查询数据库中的数据的方法。
- (3)Database数据库类,用于保存数据库并作为应用持久性数据底层连接的主要访问点;
三者关系
Entity:一个Entity对应数据库中的一张表。Entity类是Sqlite表结构对Java类的映射,在Java中可以看作一个Model类。
Dao:数据访问对象(Data Access Objects),我们通过它来访问数据。
一个Entity代表一张表,而每张表都需要一个Dao对象,用于对表进行增删改查;
Room数据库在被实例化之后我们就可以通过数据库实例获取Dao对象,然后通过Dao进行数据库操作。
一、添加依赖
def room_version = "2.4.2"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
二、创建实体类,一个实体类对应数据库中的一张表
package com.example.savedata;import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;@Entity
public class Student {@PrimaryKey(autoGenerate = true)public int id;public String stuName;public int stuAge;public int score;@Ignorepublic Student(int id, String stuName, int stuAge, int score) {this.id = id;this.stuName = stuName;this.stuAge = stuAge;this.score = score;}//Ignore亦可注解字段,让Room忽略此方法或者字段//由于Room只能识别一个构造器,如果需要定义多个构造器,可以使用Ignore注解让Room忽略这个构造器//Room不会持久化被注解Ignore标记过的字段public Student(String stuName, int stuAge, int score) {this.stuName = stuName;this.stuAge = stuAge;this.score = score;}@Overridepublic String toString() {return "Student{" +"id=" + id +", stuName='" + stuName + '\'' +", stuAge=" + stuAge +", score=" + score +'}';}
}
三、数据访问对象 (DAO)
- 定义数据访问对象 (
DAO
),提供可用于插入、删除、更新和查询数据库中的数据的方法
package com.example.savedata;import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;import java.util.List;@Dao
public interface StudentDao {//插入数据@Insertpublic void insertStu(Student... students);@Deletepublic void deleteStu(Student... students);@Updatepublic void updateStu(Student... students);//查询所有@Query("select * from student")public List<Student> queryStu();@Query("select * from student where stuName=:name")public List<Student> queryStuByName(String name);@Query("select * from student where id=:id")public Student queryStuById(int id);
}
四、数据库类
定义数据库配置,并作为应用对持久性数据的主要访问点。
数据库类必须满足以下条件:
(1)该类必须带有 @Database 注解,该注解包含列出所有与数据库关联的数据实体的 entities 数组;
(2)该类必须是一个抽象类,用于扩展 RoomDatabase;
(3)对于与数据库关联的每个 DAO 类,数据库类必须定义一个具有零参数的抽象方法,并返回 DAO 类的实例。
注意:
(1)如果您的应用在单个进程中运行,在实例化 AppDatabase 对象时应遵循单例设计模式。每个 RoomDatabase 实例的成本相当高,而您几乎不需要在单个进程中访问多个实例;
(2)如果您的应用在多个进程中运行,请在数据库构建器调用中包含 enableMultiInstanceInvalidation()。这样,如果您在每个进程中都有一个 AppDatabase 实例,可以在一个进程中使共享数据库文件失效,并且这种失效会自动传播到其他进程中 AppDatabase 的实例。
package com.example.savedata;import android.content.Context;import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;@Database(entities = {Student.class},version = 1)
public abstract class StuDatabase extends RoomDatabase {private static final String DATABASE_NAME = "student_db";private static StuDatabase databaseInstance;//结合单例模式完成创建数据库实例public static synchronized StuDatabase getDatabaseInstance(Context context) {if (databaseInstance == null) {databaseInstance = Room.databaseBuilder(context.getApplicationContext(),StuDatabase.class,DATABASE_NAME).build();}return databaseInstance;}//将第四步创建的Dao对象以抽象方法的形式返回public abstract StudentDao getStudentDao();
}
五、界面
<?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=".MainActivity"><EditTextandroid:id="@+id/etName"android:layout_width="match_parent"android:layout_height="wrap_content"android:ems="10"android:hint="请输入姓名"android:inputType="textPersonName"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><EditTextandroid:id="@+id/etAge"android:layout_width="match_parent"android:layout_height="wrap_content"android:ems="10"android:hint="请输入年龄"android:inputType="textPersonName"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/etName" /><EditTextandroid:id="@+id/etScore"android:layout_width="match_parent"android:layout_height="wrap_content"android:ems="10"android:hint="请输入成绩"android:inputType="textPersonName"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/etAge" /><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"app:layout_constraintGuide_percent="0.24" /><Buttonandroid:id="@+id/btnInsertData"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="插入数据"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="@+id/guideline2" /><Buttonandroid:id="@+id/btnDeleteData"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="删除数据"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.501"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/btnInsertData" /><Buttonandroid:id="@+id/btnQueryData"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="查询数据"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/btnDeleteData" /><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"app:layout_constraintGuide_percent="0.5" /><TextViewandroid:id="@+id/tvData"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="数据表中的数据"android:gravity="center"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="@+id/guideline4" /></androidx.constraintlayout.widget.ConstraintLayout>
六、实现(对数据的操作必须在子线程中,否则程序崩溃)
package com.example.savedata;import androidx.appcompat.app.AppCompatActivity;import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;import java.util.List;public class MainActivity extends AppCompatActivity {private EditText etName;private EditText etAge;private EditText etScore;private Button btnInsertData;private Button btnDeleteData;private Button btnQueryData;private TextView tvData;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();btnInsertData.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {insertData();}});btnDeleteData.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {deleteData();}});btnQueryData.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {queryData();}});}private void insertData() {new Thread(new Runnable() {@Overridepublic void run() {String stuName = etName.getText().toString();int stuAge = Integer.parseInt(etAge.getText().toString());int score = Integer.parseInt(etScore.getText().toString());Student student1= new Student(stuName,stuAge,score);StudentDao dao = StuDatabase.getDatabaseInstance(MainActivity.this).getStudentDao();dao.insertStu(student1);}}).start();}private void deleteData() {}private void queryData() {new Thread(new Runnable() {@Overridepublic void run() {StudentDao dao = StuDatabase.getDatabaseInstance(MainActivity.this).getStudentDao();List<Student> students = dao.queryStu();String studentsAll ="";for(int i =0;i<students.size();i++){String studentInfo = students.get(i).toString();studentsAll = studentsAll+"\n"+studentInfo;}dispalayData(studentsAll);}}).start();}private void dispalayData(String studentsAll) {runOnUiThread(new Runnable() {@Overridepublic void run() {tvData.setText(studentsAll);}});}private void initView() {etName= findViewById(R.id.etName);etAge = findViewById(R.id.etAge);etScore = findViewById(R.id.etScore);btnInsertData = findViewById(R.id.btnInsertData);btnDeleteData = findViewById(R.id.btnDeleteData);btnQueryData = findViewById(R.id.btnQueryData);tvData = findViewById(R.id.tvData);}}