AndroidJetPack应用指南学习笔记4————Room的简单使用
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标签用来告诉系统忽略该字段或者方法。
-
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删除
[email protected]注解属性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.项目源码地址如下:https://gitee.com/jackning_admin/room-demo