1.在Android中采用Sqlite作为数据库存储。Sqlite代码写起来繁琐且容易出错,所以开源社区里逐渐出现了各种ORM(Object Relational Mapping)库。这些开源ORM库都是为了方便Sqlite的使用,包括数据库的创建,升级,增删改查等。常见的ORM有ORMLite,GreenDAO等。Google也意识到了推出自家ORM的必要性,于是有了Room。
2.Room 包含 3 个主要组件:
-
数据库:包含数据库持有者,并作为应用已保留的持久关系型数据的底层连接的主要接入点。使用 @Database 注释的类应满足以下条件:是扩展 RoomDatabase 的抽象类。在注释中添加与数据库关联的实体列表。包含具有 0 个参数且返回使用 @Dao 注释的类的抽象方法。 在运行时,可以通过调用Room.databaseBuilder()或 Room.inMemoryDatabaseBuilder() 获取 Database 的实例。
-
Entity:表示数据库中的表。
-
DAO:包含用于访问数据库的方法。
应用使用 Room 数据库来获取与该数据库关联的数据访问对象 (DAO)。然后,应用使用每个 DAO 从数据库中获取实体,然后再将对这些实体的所有更改保存回数据库中。最后,应用使用实体来获取和设置与数据库中的表列相对应的值。
3.Room中常用注解说明:
-
@Entity:这是一个Model类,对应于数据库中的一张表。Entity类是Sqlite表结构在Java类的映射。
-
@Dao:(Data Access Objects)数据访问对象,顾名思义,我们可以通过它来访问数据。一个Entity代表着一张表,而每张表都需要一个Dao对象,以方便对这张表进行各种操作(增删改查)
-
@Database:数据库对象,一般写成单例模式
4.Entity中的常用注解:
-
属性:tableName:设置表名字。默认是类的名字。indices:设置索引。inheritSuperIndices:父类的索引是否会自动被当前类继承。
-
@foreignKeys:设置外键。
-
@PrimaryKey标签用于指定该字段作为表的主键。
-
@ColumnInfo标签可用于设置该字段存储在数据库表中的名字并指定字段的类型。
-
@Ignore标签用来告诉系统忽略该字段或者方法。
5.@ForeignKey属性:
-
entity:parent实体类(引用外键的表的实体)。
-
parentColumns:parent外键列(要引用的外键列)。
-
childColumns:child外键列(要关联的列)。
-
onDelete:默认NO_ACTION,当parent里面有删除操作的时候,child表可以做的Action动作有:
1. NO_ACTION:当parent中的key有变化的时候child不做任何动作。
2. RESTRICT:当parent中的key有依赖的时候禁止对parent做动作,做动作就会报错。
3. SET_NULL:当paren中的key有变化的时候child中依赖的key会设置为NULL。
4. SET_DEFAULT:当parent中的key有变化的时候child中依赖的key会设置为默认值。
5. CASCADE:当parent中的key有变化的时候child中依赖的key会跟着变化。
-
onUpdate:默认NO_ACTION,当parent里面有更新操作的时候,child表需要做的动作。Action动作方式和onDelete是一样的。
-
deferred:默认值false,在事务完成之前,是否应该推迟外键约束。这个怎么理解,当我们启动一个事务插入很多数据的时候,事务还没完成之前。当parent引起key变化的时候。可以设置deferred为ture。让key立即改变。
6.Dao中常用的注解:
-
@Query查询
-
@Insert插入
-
@Update更新
-
@Delete删除
7.@Insert注解属性onConflict:
默认值是OnConflictStrategy.ABORT,表示当插入有冲突的时候的处理策略。
OnConflictStrategy封装了Room解决冲突的相关策略:
-
OnConflictStrategy.REPLACE:冲突策略是取代旧数据同时继续事务。
-
OnConflictStrategy.ROLLBACK:冲突策略是回滚事务
-
OnConflictStrategy.ABORT:冲突策略是终止事务。
-
OnConflictStrategy.FAIL:冲突策略是事务失败。
-
OnConflictStrategy.IGNORE:冲突策略是忽略冲突。
8.Room在项目中的引入,在app的build.gradle中加入room的相关依赖:
implementation "androidx.room:room-runtime:2.2.5"
annotationProcessor "androidx.room:room-compiler:2.2.5"
9.创建一个学生实体类,创建一张表
package com.example.roomdemo.entity;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
/**
* @author: njb
* @date: 2020/8/28 0028 0:16
* @desc:
*/
@Entity(tableName = "student")
public class Student {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)
public int id;
@ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)
public String name;
@ColumnInfo(name = "age", typeAffinity = ColumnInfo.TEXT)
public String age;
/**
* Room会使用这个构造器来存储数据,也就是当你从表中得到Student对象时候,Room会使用这个构造器
*/
public Student(int id, String name, String age) {
this.id = id;
this.name = name;
this.age = age;
}
/**
* 由于Room只能识别和使用一个构造器,如果希望定义多个构造器,你可以使用Ignore标签,让Room忽略这个构造器
* 同样,@Ignore标签还可用于字段,使用@Ignore标签标记过的字段,Room不会持久化该字段的数据
*/
@Ignore
public Student(String name, String age) {
this.name = name;
this.age = age;
}
}
10.创建dao文件接口:
package com.example.roomdemo.db;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;
import com.example.roomdemo.entity.Student;
import java.util.List;
/**
* @author: njb
* @date: 2020/8/28 0028 0:17
* @desc:
*/
@Dao
public interface StudentDao {
@Insert
void insertStudent(Student student);
@Delete
void deleteStudent(Student student);
@Update
void updateStudent(Student student);
@Query("SELECT * FROM student")
List<Student> getStudentList();
@Query("SELECT * FROM student WHERE id = :id")
Student getStudentById(int id);
}
11.定义好Dao和实体类后,创建数据库:
package com.example.roomdemo.db;
import android.content.Context;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import com.example.roomdemo.entity.Student;
/**
* @author: njb
* @date: 2020/8/28 0028 0:19
* @desc:
*/
@Database(entities = {Student.class}, version = 1)
public abstract class MyDatabase extends RoomDatabase {
private static final String DATABASE_NAME = "student_db";
private static MyDatabase databaseInstance;
public static synchronized MyDatabase getInstance(Context context) {
if (databaseInstance == null) {
databaseInstance = Room
.databaseBuilder(context.getApplicationContext(), MyDatabase.class, DATABASE_NAME)
.build();
}
return databaseInstance;
}
public abstract StudentDao studentDao();
}
12.数据库的使用:
//数据库初始化:
//插入数据
//查询数据
//删除数据
//更新数据
13.MainActiivty完整代码如下:
package com.example.roomdemo;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import com.example.roomdemo.adapter.StudentAdapter;
import com.example.roomdemo.db.MyDatabase;
import com.example.roomdemo.entity.Student;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private MyDatabase myDatabase;
private List<Student> studentList;
private StudentAdapter studentAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initDataBase();
initAdapter();
}
private void initAdapter() {
ListView lvStudent = findViewById(R.id.lvStudent);
studentList = new ArrayList<>();
studentAdapter = new StudentAdapter(MainActivity.this, studentList);
lvStudent.setAdapter(studentAdapter);
lvStudent.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
updateOrDeleteDialog(studentList.get(position));
return false;
}
});
}
private void updateOrDeleteDialog(final Student student) {
final String[] options = new String[]{"更新", "删除"};
new AlertDialog.Builder(MainActivity.this)
.setTitle("")
.setItems(options, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
openUpdateStudentDialog(student);
} else if (which == 1) {
new DeleteStudentTask(student).execute();
}
}
}).show();
}
private void initDataBase() {
myDatabase = MyDatabase.getInstance(MainActivity.this);
new QueryStudentTask().execute();
}
public void insertData(View view) {
//myDatabase.studentDao().insertStudent(new Student(name, age));
}
public void updateData(View view) {
// myDatabase.studentDao().updateStudent(new Student(id, name, age));
}
public void deleteData(View view) {
//myDatabase.studentDao().deleteStudent(new Student(id, name, age));
}
public void queryData(View view) {
}
public void addStudent(View view) {
openAddStudentDialog();
}
private void openAddStudentDialog() {
View customView = this.getLayoutInflater().inflate(R.layout.dialog_layout_student, null);
final EditText etName = customView.findViewById(R.id.etName);
final EditText etAge = customView.findViewById(R.id.etAge);
final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
AlertDialog dialog = builder.create();
dialog.setTitle("Add Student");
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (TextUtils.isEmpty(etName.getText().toString()) || TextUtils.isEmpty(etAge.getText().toString())) {
Toast.makeText(MainActivity.this, "输入不能为空", Toast.LENGTH_SHORT).show();
} else {
new InsertStudentTask(etName.getText().toString(), etAge.getText().toString()).execute();
}
}
});
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "CANCEL", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
dialog.setView(customView);
dialog.show();
}
private void openUpdateStudentDialog(final Student student) {
if (student == null) {
return;
}
View customView = this.getLayoutInflater().inflate(R.layout.dialog_layout_student, null);
final EditText etName = customView.findViewById(R.id.etName);
final EditText etAge = customView.findViewById(R.id.etAge);
etName.setText(student.name);
etAge.setText(student.age);
final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
AlertDialog dialog = builder.create();
dialog.setTitle("Update Student");
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (TextUtils.isEmpty(etName.getText().toString()) || TextUtils.isEmpty(etAge.getText().toString())) {
Toast.makeText(MainActivity.this, "输入不能为空", Toast.LENGTH_SHORT).show();
} else {
new UpdateStudentTask(student.id, etName.getText().toString(), etAge.getText().toString()).execute();
}
}
});
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "CANCEL", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
dialog.setView(customView);
dialog.show();
}
private class InsertStudentTask extends AsyncTask<Void, Void, Void> {
String name;
String age;
public InsertStudentTask(final String name, final String age) {
this.name = name;
this.age = age;
}
@Override
protected Void doInBackground(Void... arg0) {
myDatabase.studentDao().insertStudent(new Student(name, age));
studentList.clear();
studentList.addAll(myDatabase.studentDao().getStudentList());
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
studentAdapter.notifyDataSetChanged();
}
}
private class UpdateStudentTask extends AsyncTask<Void, Void, Void> {
int id;
String name;
String age;
public UpdateStudentTask(final int id, final String name, final String age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
protected Void doInBackground(Void... arg0) {
myDatabase.studentDao().updateStudent(new Student(id, name, age));
studentList.clear();
studentList.addAll(myDatabase.studentDao().getStudentList());
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
studentAdapter.notifyDataSetChanged();
}
}
private class DeleteStudentTask extends AsyncTask<Void, Void, Void> {
Student student;
public DeleteStudentTask(Student student) {
this.student = student;
}
@Override
protected Void doInBackground(Void... arg0) {
myDatabase.studentDao().deleteStudent(student);
studentList.clear();
studentList.addAll(myDatabase.studentDao().getStudentList());
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
studentAdapter.notifyDataSetChanged();
}
}
private class QueryStudentTask extends AsyncTask<Void, Void, Void> {
public QueryStudentTask() {
}
@Override
protected Void doInBackground(Void... arg0) {
studentList.clear();
studentList.addAll(myDatabase.studentDao().getStudentList());
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
studentAdapter.notifyDataSetChanged();
}
}
}
14.最终实现的效果图如下:
15.项目源码地址如下:smile drily/RoomDemo