Android Realm数据库
在本教程中,我们将讨论Realm数据库的基础知识,并将其在我们的Android应用程序中进行离线数据存储。
Android Realm数据库
Realm是数据库的完美替代SQLite。
这是专为移动平台设计的NoSQL数据库。
它的核心包括一个自包含的C ++库。
它同时支持Android和iOS。
领域的优点
简洁性–与SQLite不同,代码更短,更简洁。
此外,无需使用SQL,您只需要在Realm中处理对象和对象树。速度–尽管底层算法复杂,但Realm可以更快地执行CRUD操作。
因为没有反序列化,所以获取对象非常快Live Objects – Realm没有复制行为。
所有提取都是延迟的,除非对它们执行某些操作,否则永远不会复制数据。
因此,在此之前,从查询中获得的只是数据指针。
因此,从Realm接收的所有对象都是数据库的代理。
因此,实现了零拷贝。
每当您需要访问数据时,您将始终获得最新的价值。
出色的文档-领域文档清晰明了,社区支持也很棒。
内置JSON支持– Realm具有JSON支持。
您可以直接从JSON设置数据,而无需创建模型类。安全性–您可以使用加密保护数据库。
响应式编程–您可以观察数据库中的更改并相应地更新UI。
将RxJava与Realm一起使用只会使其变得更加简单和有趣。内置适配器– Realm具有适用于Android UI组件的适配器类。
领域的缺点
无自动递增–您无法在Realm中自动递增值。
对模型类的限制–除了getter setter方法外,您无法覆盖诸如Realm Model类中的hashcode和equals之类的方法。
线程处理–不能将真实模型类从一个线程传递到另一个线程。
因此,您将不得不在其他线程上再次查询该类。
在Android中配置领域
在您的根目录build.gradle中添加以下类路径:
buildscript { ... dependencies { ... classpath 'io.realm:realm-gradle-plugin:3.2.1' } }
将以下插件添加到应用的" build.gradle"中
apply plugin: 'realm-android'
创建一个领域实例
要创建一个Realm实例,请执行以下操作:
Realm mRealm = Realm.getInstance(context);
我们也可以在getInstance()内部传递一个RealmConfiguration实例。
RealmConfiguration config = new RealmConfiguration.Builder() .name("test.db") .schemaVersion(1) .deleteRealmIfMigrationNeeded() .build();
创建领域模型类
要创建Model类,请使用RealmObject对其进行扩展。
主键可以是String或者整数类型,并带有@ PrimaryKey
注释。
以下是领域模型类上常用的一些注释:
@首要的关键
@Required –不能为空
@Index –在查询中使用的字段上添加它。
它使查询速度提高了4倍。@忽视
将数据写入领域
您可以通过以下方式将数据写入Realm:
Realm realm = Realm.getDefaultInstance(); realm.beginTransaction(); realm.copyToRealm(realmModelInstance) realm.commitTransaction();
但是,上述方法存在问题。
如果失败,它不会取消交易。
因此,不建议将数据插入数据库。
方法" executeTranscation"或者" executeTranscationAsync"会自动处理取消交易。
Realm realm = Realm.getDefaultInstance(); realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { realm.insertOrUpdate(realmModelInstance); } });
同样,我们可以在executeTranscation
内部添加一个try-catch来捕获异常。
但是,较早的方法忽略了try-catch。
如果主键不存在,则使用" insertOrUpdate"或者" copyToRealmOrUpdate"进行插入;如果主键存在,则用于更新当前对象。
从领域阅读
RealmResults<RealModelClass> results = realm.where(RealModelClass.class).findAll();
同样,在execute方法中使用此代码也是个好习惯。
从领域删除
mRealm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { RealmResults<RealModelClass> results = realm.where(RealModelClass.class).findAll(); results.deleteAllFromRealm(); } });
以下是可用于删除结果的其他方法:
RealmList是RealmObjects的内置集合,用于模型一对多关系。
RealmList无法支持非领域对象(例如Long,String,Integer)。
在下一节中,我们将创建一个基本的Android应用程序,该应用程序使用Realm并执行CRUD操作。
代码
下面给出了activity_main.xml布局的代码:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:tools="https://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="8dp" android:orientation="horizontal" android:weightSum="2" tools:context=".MainActivity"> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical"> <EditText android:id="@+id/inName" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Name" <EditText android:id="@+id/inAge" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Age" android:inputType="number" <EditText android:id="@+id/inSkill" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Skill" <Button android:id="@+id/btnAdd" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="ADD" <TextView android:id="@+id/textViewEmployees" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Result:" <Button android:id="@+id/btnRead" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="READ" <Button android:id="@+id/btnUpdate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="UPDATE" </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical"> <TextView android:id="@+id/txtFilterByAge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Result:" <Button android:id="@+id/btnFilterByAge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="EMPLOYEE OVER 25" <TextView android:id="@+id/txtFilterBySkill" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Result:" <Button android:id="@+id/btnDelete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="DELETE BY NAME" <Button android:id="@+id/btnDeleteWithSkill" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="DELETE ALL WITH SKILL" </LinearLayout> </LinearLayout>
在MyApplication.java内部,是我们初始化领域的地方。
package com.theitroad.androidrealmdatabase; import android.app.Application; import io.realm.Realm; import io.realm.RealmConfiguration; public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Realm.init(getApplicationContext()); RealmConfiguration config = new RealmConfiguration.Builder() .deleteRealmIfMigrationNeeded() .build(); Realm.setDefaultConfiguration(config); } }
Employee.java类的代码如下:
package com.theitroad.androidrealmdatabase; import io.realm.RealmList; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; import io.realm.annotations.Required; public class Employee extends RealmObject { public static final String PROPERTY_NAME = "name"; public static final String PROPERTY_AGE = "age"; @PrimaryKey @Required public String name; public int age; public RealmList<Skill> skills; }
下面给出了Skill.java类的代码:
package com.theitroad.androidrealmdatabase; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; import io.realm.annotations.Required; public class Skill extends RealmObject { public static final String PROPERTY_SKILL = "skillName"; @PrimaryKey @Required public String skillName; }
MainActivity.java的代码如下:
package com.theitroad.androidrealmdatabase; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import io.realm.Realm; import io.realm.RealmList; import io.realm.RealmResults; import io.realm.exceptions.RealmPrimaryKeyConstraintException; public class MainActivity extends AppCompatActivity implements View.OnClickListener { Button btnAdd, btnRead, btnUpdate, btnDelete, btnDeleteWithSkill, btnFilterByAge; EditText inName, inAge, inSkill; TextView textView, txtFilterBySkill, txtFilterByAge; Realm mRealm; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); mRealm = Realm.getDefaultInstance(); } private void initViews() { btnAdd = findViewById(R.id.btnAdd); btnAdd.setOnClickListener(this); btnRead = findViewById(R.id.btnRead); btnRead.setOnClickListener(this); btnUpdate = findViewById(R.id.btnUpdate); btnUpdate.setOnClickListener(this); btnDelete = findViewById(R.id.btnDelete); btnDelete.setOnClickListener(this); btnDeleteWithSkill = findViewById(R.id.btnDeleteWithSkill); btnDeleteWithSkill.setOnClickListener(this); btnFilterByAge = findViewById(R.id.btnFilterByAge); btnFilterByAge.setOnClickListener(this); textView = findViewById(R.id.textViewEmployees); txtFilterBySkill = findViewById(R.id.txtFilterBySkill); txtFilterByAge = findViewById(R.id.txtFilterByAge); inName = findViewById(R.id.inName); inAge = findViewById(R.id.inAge); inSkill = findViewById(R.id.inSkill); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.btnAdd: addEmployee(); break; case R.id.btnRead: readEmployeeRecords(); break; case R.id.btnUpdate: updateEmployeeRecords(); break; case R.id.btnDelete: deleteEmployeeRecord(); break; case R.id.btnDeleteWithSkill: deleteEmployeeWithSkill(); break; case R.id.btnFilterByAge: filterByAge(); break; } } private void addEmployee() { Realm realm = null; try { realm = Realm.getDefaultInstance(); realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { try { if (!inName.getText().toString().trim().isEmpty()) { Employee employee = new Employee(); employee.name = inName.getText().toString().trim(); if (!inAge.getText().toString().trim().isEmpty()) employee.age = Integer.parseInt(inAge.getText().toString().trim()); String languageKnown = inSkill.getText().toString().trim(); if (!languageKnown.isEmpty()) { Skill skill = realm.where(Skill.class).equalTo(Skill.PROPERTY_SKILL, languageKnown).findFirst(); if (skill == null) { skill = realm.createObject(Skill.class, languageKnown); realm.copyToRealm(skill); } employee.skills = new RealmList<>(); employee.skills.add(skill); } realm.copyToRealm(employee); } } catch (RealmPrimaryKeyConstraintException e) { Toast.makeText(getApplicationContext(), "Primary Key exists, Press Update instead", Toast.LENGTH_SHORT).show(); } } }); } finally { if (realm != null) { realm.close(); } } } private void readEmployeeRecords() { mRealm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { RealmResults<Employee> results = realm.where(Employee.class).findAll(); textView.setText(""); for (Employee employee : results) { textView.append(employee.name + " age: " + employee.age + " skill: " + employee.skills.size()); } } }); } private void updateEmployeeRecords() { mRealm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { if (!inName.getText().toString().trim().isEmpty()) { Employee employee = realm.where(Employee.class).equalTo(Employee.PROPERTY_NAME, inName.getText().toString()).findFirst(); if (employee == null) { employee = realm.createObject(Employee.class, inName.getText().toString().trim()); } if (!inAge.getText().toString().trim().isEmpty()) employee.age = Integer.parseInt(inAge.getText().toString().trim()); String languageKnown = inSkill.getText().toString().trim(); Skill skill = realm.where(Skill.class).equalTo(Skill.PROPERTY_SKILL, languageKnown).findFirst(); if (skill == null) { skill = realm.createObject(Skill.class, languageKnown); realm.copyToRealm(skill); } if (!employee.skills.contains(skill)) employee.skills.add(skill); } } }); } private void deleteEmployeeRecord() { mRealm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Employee employee = realm.where(Employee.class).equalTo(Employee.PROPERTY_NAME, inName.getText().toString()).findFirst(); if (employee != null) { employee.deleteFromRealm(); } } }); } private void deleteEmployeeWithSkill() { mRealm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { RealmResults<Employee> employees = realm.where(Employee.class).equalTo("skills.skillName", inSkill.getText().toString().trim()).findAll(); employees.deleteAllFromRealm(); } }); } private void filterByAge() { mRealm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { RealmResults<Employee> results = realm.where(Employee.class).greaterThanOrEqualTo(Employee.PROPERTY_AGE, 25).findAllSortedAsync(Employee.PROPERTY_NAME); txtFilterByAge.setText(""); for (Employee employee : results) { txtFilterByAge.append(employee.name + " age: " + employee.age + " skill: " + employee.skills.size()); } } }); } @Override protected void onDestroy() { super.onDestroy(); if (mRealm != null) { mRealm.close(); } } }
不要忘记关闭Realm实例!
当您单击不存在的其他技能进行更新时,它会创建该技能并将其添加到RealmList。