ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

Android Realm数据库使用,字节跳动+腾讯+华为+小米+阿里面试题分享

2022-01-17 11:59:35  阅读:148  来源: 互联网

标签:面试题 realm 查询 new Realm Android RealmConfiguration 主键


字段类型

Model类中可以包含的字段类型包括基本数据类型(及它们的装箱类型)和Date类, 另外也可以包含RealmObject的子类或者是RealmList<? extends RealmObject>.

字段性质

在字段上加注解可以定义字段的性质:

@Required表明字段非null.

原生类型和RealmList类型默认是非null的.

RealmObject字段永远是可以为null的.

@Ignore表示字段不会被存储.

@Index加索引.

@PrimaryKey加主键, 主键只能有一个, 主键默认加索引.

但是注意主键默认没有加@Required, 如果主键要求非null, 需要显式添加@Required.

主键使用

有主键才能使用copyToRealmOrUpdate()这个方法.

主键类型必须是String或者整型(byte, short, int, long)或者它们的装箱类型(Byte, Short, Integer, Long).

有主键的对象创建的时候不能使用createObject(Class<E> clazz)方法, 而应该使用createObject(Class<E> clazz, Object primaryKeyValue)附上主键.

或者用

copyToRealm(obj)copyToRealmOrUpdate(obj), 前者遇到主键冲突时会崩溃, 后者遇到主键冲突会更新已有对象.

自动更新的对象

Realm中的数据对象是自动更新(Auto-Updating)的, 对象一旦被查询出来, 后续发生的任何数据改变也会立即反映在结果中, 不需要刷新对象.

这是一个非常有用的特性, 结合数据变化的通知可以很方便地刷新UI.

关系

Realm model对象间可以很方便地建立关系.

你可以在Model中存储另一个对象的引用, 建立多对一的关系; 也可以存储一组对象RealmList<T>, 建立一对多或多对多的关系.

RealmList<T>的getter永远也不会返回null, 它只会返回一个为空的list.

把这个字段设置为null可以清空这个list.

初始化


Realm在使用之前需要调用初始化:

Realm.init(context);

建议把它放在Application的onCreate()里.

配置

配置类: RealmConfiguration定义了Realm的创建配置.

最基本的配置:

RealmConfiguration config = new RealmConfiguration.Builder().build();

它会创建一个叫default.realm的文件, 放在Context.getFilesDir()的目录下.

如果我们想自定义一个配置, 可以这样写:

// The RealmConfiguration is created using the builder pattern. // The Realm file will be located in Context.getFilesDir() with name “myrealm.realm” RealmConfiguration config = new RealmConfiguration.Builder() .name(“myrealm.realm”) .encryptionKey(getKey()) .schemaVersion(42) .modules(new MySchemaModule()) .migration(new MyMigration()) .build(); // Use the config Realm realm = Realm.getInstance(config);

所以我们是可以有多个配置, 访问多个Realm实例的.

我们可以把配置设置为默认配置:

Realm.init(this); RealmConfiguration config = new RealmConfiguration.Builder().build(); Realm.setDefaultConfiguration(config);

之后用Realm.getDefaultInstance()取到的就是这个默认配置对应的实例.

数据库迁移


迁移的策略是通过config指定的:

RealmConfiguration config = new RealmConfiguration.Builder() .schemaVersion(2) // Must be bumped when the schema changes .migration(new MyMigration()) // Migration to run instead of throwing an exception .build()

其中MyMigration实现了RealmMigration接口, 在migrate()方法中根据新旧版本号进行一步一步地升级.

具体例子见Migration.

开发的时候为了方便我用的是.deleteRealmIfMigrationNeeded(), 这样在需要数据库迁移的时候直接就删了数据重新开始了.

关于Realm的close()


一个打开的Realm实例会持有一些资源, 有一些是Java不能自动管理的, 所以就需要打开实例的代码负责在不需要的时候将其关闭.

Realm的instance是引用计数的(reference counted cache), 在同一个线程中获取后续实例是免费的, 但是底层的资源只有当所有实例被释放了之后才能释放. 也即你调用了多少次getInstance(), 就需要调用相应次数的close()方法.

比较建议的方法是在Activity或Fragment的生命周期中处理Realm实例的开启和释放:

  • 在Activity的onCreate()getInstance()onDestroy()close().

  • 在Fragment的onCreateView()getInstance()onDestroyView()close().

如果多个Fragment相关的都是同一个数据库实例, 那么在Activity中处理更好一些.

写操作一般的流程是这样:

// Obtain a Realm instance Realm realm = Realm.getDefaultInstance(); realm.beginTransaction(); //… add or update objects here … realm.commitTransaction();

这里创建对象可以用createObject()方法或者copyToRealm()方法.

前者是先创建再set值, 后者是先new对象再更新数据库.

如果不想自己处理beginTransaction()cancelTransaction()commitTransaction(), 可以直接调用realm.executeTransaction()方法:

realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { User user = realm.createObject(User.class); user.setName(“John”); user.setEmail(“john@corporation.com”); } });

异步

因为transactions之间是互相阻塞的.

异步执行可以用这个方法:

realm.executeTransactionAsync(new Realm.Transaction() { @Override public void execute(Realm bgRealm) { User user = bgRealm.createObject(User.class); user.setName(“John”); user.setEmail(“john@corporation.com”); } }, new Realm.Transaction.OnSuccess() { @Override public void onSuccess() { // Transaction was a success. } }, new Realm.Transaction.OnError() { @Override public void one rror(Throwable error) { // Transaction failed and was automatically canceled. } });

这两个回调是Optional的, 它们只能在有Looper的线程调用.

注意: 这个方法的返回值对象可以用于在Activity/Fragment生命周期结束的时候取消未完的操作.

删除和更新

所有的写操作都要放在transaction中进行, 如上, 不同的操作只是其中具体方法不同.

删除操作:

final RealmResults
users = getUsers(); // method 1: users.get(0).deleteFromRealm(); // method 2: users.deleteFromRealm(0); // delete all users.deleteAllFromRealm();

更新操作:

realm.copyToRealmOrUpdate(obj);

注意: 这个方法需要Model有主键, 会更新obj的主键对应的对象, 如果不存在则新建对象.

查询

查询可以流式地写:

// Or alternatively do the same all at once (the “Fluent interface”): RealmResults result2 = realm.where(User.class) .equalTo(“name”, “John”) .or() .equalTo(“name”, “Peter”) .findAll();

查询条件默认是and的关系, or则需要显式指定.

这个RealmResults是继承Java的AbstractList的, 是有序的集合, 可以通过索引访问.

RealmResults永远不会为null, 当查不到结果时, 它的size()返回0.

查询的线程

基本上所有的查询都是很快进行的, 足够在UI线程上同步进行.

所以绝大多数情况在UI线程上使用findAll()是没有问题的.

如果你要进行非常复杂的查询, 或者你的查询是在非常大的数据集上进行的, 你可以选择异步查询, 使用findAllAsync().

查询条件是一个集合 -> in()

如果想要查询的某一个字段的值是在一个集合中, 比如我有一个id的集合, 我现在想把id在这个集合中的项目全都查出来, 这就可以使用in操作符:

RealmResults toDeleteLists = realm.where(TodoList.class).in(“id”, ids).findAll();

链式查询

查询的时候可以利用link或关系来查询, 比如一个Person类中含有一个RealmList<Dog> dogs的字段.

()`是没有问题的.

如果你要进行非常复杂的查询, 或者你的查询是在非常大的数据集上进行的, 你可以选择异步查询, 使用findAllAsync().

查询条件是一个集合 -> in()

如果想要查询的某一个字段的值是在一个集合中, 比如我有一个id的集合, 我现在想把id在这个集合中的项目全都查出来, 这就可以使用in操作符:

RealmResults toDeleteLists = realm.where(TodoList.class).in(“id”, ids).findAll();

链式查询

查询的时候可以利用link或关系来查询, 比如一个Person类中含有一个RealmList<Dog> dogs的字段.

标签:面试题,realm,查询,new,Realm,Android,RealmConfiguration,主键
来源: https://blog.csdn.net/m0_66145060/article/details/122536891

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有