Android Realm数据库开发探索(二)

同步查询

  • Realm 支持以下查询条件:
  • between()、greaterThan()、lessThan()、greaterThanOrEqualTo() 和 lessThanOrEqualTo()
    equalTo() 和 notEqualTo()
    contains()、beginsWith() 和 endsWith()
    isNull() 和 isNotNull()
    isEmpty() 和 isNotEmpty()

  • 修饰符
    字符串查询条件可以通过使用 Case.INSENSITIVE 修饰符来忽略字母 A-Z 和 a-z 的大小写。
  • 逻辑运算符
    每个查询条件都会被被隐式地被逻辑和(&)组合在一起,而逻辑或(or)需要显式地去执行 or()。
    将查询条件组合在一起,使用 beginGroup()(相当于左括号)和 endGroup()(相当于右括号):
  • RealmResults<User> r = realm.where(User.class)
                                .greaterThan("id", 10)  //这里是逻辑和
                                .beginGroup()
                                    .equalTo("name", "Peter")
                                    .or()//这里是逻辑或
                                    .contains("name", "Jo")
                                .endGroup()
                                .findAll();

    此外,也可以用 not() 否定一个条件。该 not() 运算符可以与 beginGroup()/endGroup() 一起使用来否定子条件。

  • 排序
    当你执行完查询获得结果后,可以对它进行排序:
  • RealmResults<User> result = realm.where(User.class).findAll();
    result = result.sort("age"); // Sort ascending
    result = result.sort("age", Sort.DESCENDING);

  • 查询例子:
  • RealmQuery<User> query = realm.where(User.class);
    query.equalTo("name", "John");
    query.or().equalTo("name", "Peter");
    RealmResults<User> result1 = query.findAll();//查询符合条件的所有对象
    
    RealmResults<User> result2 = realm.where(User.class)
                                      .equalTo("name", "John")
                                      .or()
                                      .equalTo("name", "Peter")
                                      .findAll();//查询符合条件的所有对象
    
    User user=realm.where(User.class).equalTo("id","1").findFirst();//查询id为1的对象
    
    RealmQuery<User> query=realm.where(User.class);
    RealmResults<User> resultList=query.findAllSorted("id", Sort.DESCENDING);//查询所有 结果倒序排列

    异步查询

    Realm支持在后台线程进行查询。如果需要进行非常复杂的查询或者在大量数据中进行查询,那么就应该使用异步查询。异步查询调用很简单,就是在同步方法的后面加Async就可以使用了。
    示例:查找名字为 “John” 或者 “Peter” 的用户。
    创建异步查询

    RealmResults<User> result = realm.where(User.class)
                                  .equalTo("name", "John")
                                  .or()
                                  .equalTo("name", "Peter")
                                  .findAllAsync();

    请注意,这里的调用并不会阻塞,而是立即返回一个 RealmResults。这很类似于标准 Java 中 Future 的概念。查询将会在后台线程中被执行,当其完成时,之前返回的 RealmResults 实例会被更新。
    如果你希望当查询完成、RealmResults 被更新时获得通知,你可以注册一个 RealmChangeListener。这个监听器会在 RealmResults 被更新时被调用(通常是在事务被提交后)。
    注册回调

    private RealmChangeListener callback = new RealmChangeListener<RealmResults<User>>() {
        @Override
        public void onChange(RealmResults<User> results) {
            // called once the query complete and on every update
        }
    };
    
    public void onStart() {
        RealmResults<User> result = realm.where(User.class).findAllAsync();
        result.addChangeListener(callback);
    }

    请在退出 Activity 或者 Fragment 时移除监听器的注册以避免内存泄漏。

    public void onStop () {
        result.removeChangeListener(callback); //移除指定的监听器
        result.removeChangeListeners(); // 移除所有的监听器
    }

    事务

    在任何时间都可以对对象进行访问和查询(读取事务是隐式的)。 所有的写操作(添加、修改和删除对象),必须包含在写入事务(transaction)中。写入事务可以提交或取消。在提交期间,所有更改都将被写入磁盘,并且,只有当所有更改可以被持久化时,提交才会成功。通过取消一个写入事务,所有更改将被丢弃。使用写入事务,会确保你的数据的一致性。

  • 事务
  • Realm realm = Realm.getDefaultInstance();//获取Realm单例
    realm.beginTransaction();//开始一个事务
    
    //... 对数据库的操作
    
    realm.commitTransaction();//提交事务
    realm.cancelTransaction();//取消事务

    请注意,写入事务之间会互相阻塞,如果一个写入事务正在进行,那么其他的线程的写入事务就会阻塞它们所在的线程。同时在 U I线程和后台线程使用写入事务有可能导致 ANR 问题。可以使用 异步事务(async transactions)以避免阻塞 UI 线程。

  • 事务执行块
    除手动调用 realm.beginTransaction()、realm.commitTransaction() 和 realm.cancelTransaction() 之外你可以使用 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");
        }
    });

  • 异步事务
    事务会相互阻塞其所在的线程,在后台线程中开启事务进行写入操作可以有效避免 UI 线程被阻塞。通过使用异步事务,Realm 会在后台线程中进行写入操作,并在事务完成时将结果传回调用线程。
  • 在UI线程中调用,有Looper对象,将异步线程的结果通过handler回调到UI线程,也就是OnSuccess,OnError回调函数会在事务成功或者失败时在UI线程执行。。

    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 onError(Throwable error) {
            // Transaction failed and was automatically canceled.
        }
    });

    在子线程中调用,没有Looper对象,在非 Looper 线程中只有空(null)回调函数被允许使用:

    RealmAsyncTask transaction = 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");
                }
            }, null,null);

    异步事务调用会返回一个 RealmAsyncTask 对象。当你退出 Activity 或者 Fragment 时可以使用该对象取消异步事务。如果你在回调函数中更新 UI,那么忘记取消异步事务可能会造成你的应用崩溃。

    public void onStop () {
        if (transaction != null && !transaction.isCancelled()) {
            transaction.cancel();
        }
    }

    删除

    删除RealmObject分两种方式,一种是继承RealmObject的对象实例,一种是实现RealmModel接口的对象实例。
    删除可以从查询结果中删除数据:

    final RealmResults<Dog> results = realm.where(Dog.class).findAll();//查询数据
    realm.executeTransaction(new Realm.Transaction() {//当对数据库进行改变数据时,必须在一个事务中
        @Override
        public void execute(Realm realm) {
            results.deleteFirstFromRealm();//删除数组的首个元素
            results.deleteLastFromRealm();//删除数组的最后一个元素
    
            Dog dog = results.get(5);
            dog.deleteFromRealm();//Dog类继承RealmObject类 删除指定下标的元素
            RealmObject.deleteFromRealm(dog );//Dog类实现RealmModel接口 删除指定下标的元素
    
    
            results.deleteAllFromRealm();//清空Dog表
        }
    });

    插入

    插入数据必须开启一个事务,然后创建一个RealmObject的对象实例,并赋值进行初始化,然后提交事务就可以插入到数据库中了。

    User user=new User();
    user.setId("1");
    user.setName("Jason");
    user.setIntro("Hello World!");
    
    Realm realm = Realm.getDefaultInstance(); //方式一 使用beginTransaction开启事务
    realm.beginTransaction();
    User reslmUser=realm.copyToRealm(user);//reslmUser指向了数据库中的数据 对该对象的修改都会保存到数据库
    realm.commitTransaction();
    
    realm.executeTransaction(new Realm.Transaction() {//方式二 使用executeTransaction 会在execute执行完自动提交或发生错误取消
       @Override
       public void execute(Realm realm) {
          User user2=realm.createObject(User.class,"1");//参数一 表名 参数二 主键值  
          user2.setName("Jason");
          user2.setIntro("Hello World!");
          }
       });

    更新

    更新操作跟插入操作差不多,前提是必须获取到RealmObject数据,可以进行查询数据获取RealmResults或者RealmObject后再进行更新操作。更新也必须开启一个事务,然后在事务中对RealmObject对象进行修改字段变量值就可以了,跟插入操作类似。

    final User user=realm.where(User.class).equalTo("id","1").findFirst();//先查询 获取RealmObject对象
    realm.executeTransaction(new Realm.Transaction() {//开启事务
      @Override
      public void execute(Realm realm) {
         user.setIntro("更新Intro");//修改数据库中所指向的对象的值 execute执行完会自动提交
         user.setName("king");
         }
      });

    支持JSON

    可以直接将 JSON 对象添加到 Realm 中,这些 JSON 对象可以是一个 String、一个 JSONObject 或者是一个 InputStream。Realm 会忽略 JSON 中存在但未定义在 Realm 模型类里的字段。单独对象可以通过 Realm.createObjectFromJson() 添加。对象列表可以通过 Realm.createAllFromJson() 添加。

    // A RealmObject that represents a city
    public class City extends RealmObject {
        private String city;
        private int id;
        // getters and setters left out ...
    }
    
    // Insert from a string
    realm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            realm.createObjectFromJson(City.class, "{ city: \"Copenhagen\", id: 1 }");
        }
    });
    
    // Insert multiple items using an InputStream
    realm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            try {
                InputStream is = new FileInputStream(new File("path_to_file"));
                realm.createAllFromJson(City.class, is);
            } catch (IOException e) {
                throw new RuntimeException();
            }
        }
    });

    Realm 解析 JSON 时遵循如下规则: * 使用包含空值(null)的 JSON 创建对象: * 对于非必须(可为空值的属性),设置其值为 null; * 对于必须(不可为空值的属性),抛出异常; * 使用包含空值(null)的 JSON 更新对象: * 对于非必须(可为空值的属性),设置其值为 null; * 对于必须(不可为空值的属性),抛出异常; * 使用不包含对应属性的 JSON: * 该属性保持不变

    监听数据改变

    Realm数据库支持在Realm实例,RealmObject 和 RealmResults 实例上添加监听器。可以通过这样的方式来监视对象和查询结果的改变,在监听对象的引用对象改变时监听器被触发。另外,当监听回调函数被调用时,相应的数据已经被更新,你不需要去做刷新操作。

    public class MyActivity extends Activity {
        private Realm realm;
        private RealmChangeListener puppiesListener;
        private RealmChangeListener dogListener;
    
        private RealmResults<Dog> puppies;
        private Dog dog;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          realm = Realm.getDefaultInstance();
          puppiesListener = new RealmChangeListener<RealmResults<Dog>>() {
            @Override
            public void onChange(RealmResults<Dog> puppies) {
                // ... do something with the updated puppies instance
            }};
    
          // Find all the puppies
          puppies = realm.where(Dog.class).lessThanOrEqualTo("age", 2).findAll();
          puppies.addChangeListener(puppiesListener);
    
          dogListener = new RealmChangeListener<Dog>() {
            @Override
            public void onChange(Dog dog) {
                // ... do something with the updated Dog instance
            }};
    
          dog = realm.where(Dog.class).equals("name", "Fido").findFirst();
          dog.addChangeListener(dogListener);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            // Remove the listeners
            puppies.removeChangeListener(puppiesListener);
            dog.removeChangeListener(dogListener);
            // Close the Realm instance.
            realm.close();
        }
    }

    Intent传递数据

    Realm并不支持直接通过intent传递RealmObject对象,官方建议只传递RealmObject 的标识符,可以是主键或某个字段。
    例如RealmObject对象实例person拥有一个主键id,可以通过intent的bundle来传递这个主键的值。

    // Assuming we had a person class with a @PrimaryKey on the 'id' field ...
    Intent intent = new Intent(getActivity(), ReceivingService.class);
    intent.putExtra("person_id", person.getId());
    getActivity().startService(intent);

    在接受方(Activty、Service、IntentService、BroadcastReceiver 及其它)从 bundle 中解析出这个主键然后打开 Realm 查询得到这个 RealmObject。

    // in onCreate(), onHandleIntent(), etc.
    String personId = intent.getStringExtra("person_id");
    Realm realm = Realm.getDefaultInstance();
    Person person = realm.where(Person.class).equalTo("id", personId).findFirst();
    // do something with the person ...
    realm.close();

    因为Realm查询速度够快了,所以再查询一次的时间消耗还是微乎其微的。

    参考资料:Realm文档:
    https://realm.io/cn/docs/java/latest/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值