Android Realm数据库

时间:2020-02-23 14:29:11  来源:igfitidea点击:

在本教程中,我们将讨论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。