zoukankan      html  css  js  c++  java
  • 【Android开发】【数据库】Realm For Android

    目录
    1、Realm简介
    2、环境配置
    3、初始化Realm
    4、创建实体
    5、增
    6、删
    7、改
    8、查
    9、异步操作
    10、数据库数据更新监听
    11、json转对象,插入数据库
    12、Demo地址 https://github.com/baitutang1221/DemoRealm-master

    2964446-3dae58683331f142.gif

    2964446-f8248e8bc078c7f0.gif

    ==========================================

    一、Realm简介

    数据库Realm,是用来替代sqlite的一种解决方案,它有一套自己的数据库存储引擎,比sqlite更轻量级,拥有更快的速度,并且具有很多现代数据库的特性,比如支持JSON,流式api,数据变更通知,自动数据同步,简单身份验证,访问控制,事件处理,最重要的是跨平台,目前已有Java,Objective C,Swift,React-Native,Xamarin这五种实现。

    二、环境配置

    (1). 在项目的build文件加上 classpath "io.realm:realm-gradle-plugin:2.0.2"

    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath "io.realm:realm-gradle-plugin:2.0.2"
        }
    }
    

    (2) 在app的build文件加上

    apply plugin: 'realm-android'
    

    三、初始化Realm

    (1) 在Application的oncreate()方法中Realm.init()

    public class MyApplication extends Application {
      @Override
      public void onCreate() {
        super.onCreate();
        Realm.init(this);
      }
    }
    

    (2)在Application的oncreate()方法中对Realm进行相关配置
    ①使用默认配置

    public class MyApplication extends Application {
      @Override
      public void onCreate() {
        super.onCreate();
        // The Realm file will be located in Context.getFilesDir() with name "default.realm"
        Realm.init(this);
        RealmConfiguration config = new RealmConfiguration.Builder().build();
        Realm.setDefaultConfiguration(config);
      }
    }
    

    ②使用自定义配置

    public class MyApplication extends Application {
      @Override
      public void onCreate() {
        super.onCreate();
        Realm.init(this);
        RealmConfiguration config = new  RealmConfiguration.Builder()
                                             .name("myRealm.realm")
                                             .deleteRealmIfMigrationNeeded()
                                             .build();
        Realm.setDefaultConfiguration(config);
      }
    }
    

    (3)在AndroidManifest.xml配置自定义的Application

    <application
      android:name=".MyApplication"
      ...
    />
    

    四、创建实体

    (1)新建一个类继承RealmObject

    public class Dog extends RealmObject {
        private String name;
        private int age;
        
        @PrimaryKey
        private String id;
    
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    }
    

    多对多的关系:

    public class Contact extends RealmObject {
        public String name;
        public RealmList<Email> emails;
    }
    
    public class Email extends RealmObject {
        public String address;
        public boolean active;
    }
    

    (2)其他相关说明

    1、支持的数据类型:
    boolean, byte, short, int, long, float, double, String, Date and byte[]
    在Realm中byte, short, int, long最终都被映射成long类型

    2、注解说明

    @PrimaryKey
    ①字段必须是String、 integer、byte、short、 int、long 以及它们的封装类Byte, Short, Integer, and Long
    ②使用了该注解之后可以使用copyToRealmOrUpdate()方法,通过主键查询它的对象,如果查询到了,则更新它,否则新建一个对象来代替。
    ③使用了该注解将默认设置(@index)注解
    ④使用了该注解之后,创建和更新数据将会慢一点,查询数据会快一点。

    @Required
    数据不能为null

    @Ignore
    忽略,即该字段不被存储到本地

    @Index
    为这个字段添加一个搜索引擎,这将使插入数据变慢、数据增大,但是查询会变快。建议在需要优化读取性能的情况下使用。

    五、增

    (1)实现方法一:事务操作

    类型一 :新建一个对象,并进行存储

    Realm realm=Realm.getDefaultInstance();
    
    realm.beginTransaction();
    User user = realm.createObject(User.class); // Create a new object
    user.setName("John");
    user.setEmail("john@corporation.com");
    realm.commitTransaction();
    

    类型二:复制一个对象到Realm数据库

    Realm realm=Realm.getDefaultInstance();
    
    User user = new User("John");
    user.setEmail("john@corporation.com");
    
    // Copy the object to Realm. Any further changes must happen on realmUser
    realm.beginTransaction();
    realm.copyToRealm(user);
    realm.commitTransaction();
    

    (2)实现方法二:使用事务块

    Realm  mRealm=Realm.getDefaultInstance();
    
    final User user = new User("John");
    user.setEmail("john@corporation.com");
    
    mRealm.executeTransaction(new Realm.Transaction() {
         @Override
         public void execute(Realm realm) {
            realm.copyToRealm(user); 
         }
     });
    

    切记,Realm数据库的主键字段不是自动增长的,如果有主键,需要自己设置,做添加的时候如果不给id字段值,默认会为0。
    后面再添加会报错,说id为0的数据已经存在。
    尤其是批量添加的时候要注意,当心出现只添加了一条记录的悲剧。

    六、删

        Realm  mRealm=Realm.getDefaultInstance();
    
        final RealmResults<Dog> dogs=  mRealm.where(Dog.class).findAll();
    
            mRealm.executeTransaction(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                
                    Dog dog=dogs.get(5);
                    dog.deleteFromRealm();
                    //删除第一个数据
                    dogs.deleteFirstFromRealm();
                    //删除最后一个数据
                    dogs.deleteLastFromRealm();
                    //删除位置为1的数据
                    dogs.deleteFromRealm(1);
                    //删除所有数据
                    dogs.deleteAllFromRealm();
                }
            });
    

    同样也可以使用同上的beginTransaction和commitTransaction方法进行删除

    七、改

    Realm  mRealm=Realm.getDefaultInstance();
    
    Dog dog = mRealm.where(Dog.class).equalTo("id", id).findFirst();
    mRealm.beginTransaction();
    dog.setName(newName);
    mRealm.commitTransaction();
    

    同样也可以用事物块来更新数据

    八、查

    (1)查询全部

    查询结果为RealmResults

        public List<Dog> queryAllDog() {
            Realm  mRealm=Realm.getDefaultInstance();
            RealmResults<Dog> dogs = mRealm.where(Dog.class).findAll();
            return mRealm.copyFromRealm(dogs);
        }
    

    (2)条件查询

        public Dog queryDogById(String id) {
            Realm  mRealm=Realm.getDefaultInstance();
            Dog dog = mRealm.where(Dog.class).equalTo("id", id).findFirst();
            return dog;
        }
    

    常见的条件如下(详细资料请查官方文档):

    可拼接查询条件如下
    //.or() 或者
    //.beginsWith() 以xxx开头
    //.endsWith() 以xxx结尾
    //.greaterThan() 大于
    //.greaterThanOrEqualTo() 大于或等于
    //.lessThan() 小于
    //.lessThanOrEqualTo() 小于或等于
    //.equalTo() 等于
    //.notEqualTo() 不等于
    //.findAll() 查询所有
    //.average() 平均值
    //.beginGroup() 开始分组
    //.endGroup() 结束分组
    //.between() 在a和b之间
    //.contains() 包含xxx
    //.count() 统计数量
    //.distinct() 去除重复
    //.findFirst() 返回结果集的第一行记录
    //.isNotEmpty() 非空串
    //.isEmpty() 为空串
    //.isNotNull() 非空对象
    //.isNull() 为空对象
    //.max() 最大值
    //.maximumDate() 最大日期
    //.min() 最小值
    //.minimumDate() 最小日期
    //.sum() 求和

    (3)对查询结果进行排序

        /**
         * query (查询所有)
         */
        public List<Dog> queryAllDog() {
            RealmResults<Dog> dogs = mRealm.where(Dog.class).findAll();
            /**
             * 对查询结果,按Id进行排序,只能对查询结果进行排序
             */
            //增序排列
            dogs=dogs.sort("id");
            //降序排列
            dogs=dogs.sort("id", Sort.DESCENDING);
            return mRealm.copyFromRealm(dogs);
        }
    

    (4)其他查询

    sum,min,max,average只支持整型数据字段

       /**
         *  查询平均年龄
         */
        private void getAverageAge() {
             double avgAge=  mRealm.where(Dog.class).findAll().average("age");
        }
    
        /**
         *  查询总年龄
         */
        private void getSumAge() {
          Number sum=  mRealm.where(Dog.class).findAll().sum("age");
            int sumAge=sum.intValue();
        }
    
        /**
         *  查询最大年龄
         */
        private void getMaxId(){
          Number max=  mRealm.where(Dog.class).findAll().max("age");
            int maxAge=max.intValue();
        }
    

    九、异步操作

    大多数情况下,Realm的增删改查操作足够快,可以在UI线程中执行操作。但是如果遇到较复杂的增删改查,或增删改查操作的数据较多时,就可以子线程进行操作。

    (1)异步增:

        private void addCat(final Cat cat) {
          RealmAsyncTask  addTask=  mRealm.executeTransactionAsync(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                    realm.copyToRealm(cat);
                }
            }, new Realm.Transaction.OnSuccess() {
                @Override
                public void onSuccess() {
                    ToastUtil.showShortToast(mContext,"收藏成功");
                }
            }, new Realm.Transaction.OnError() {
                @Override
                public void onError(Throwable error) {
                    ToastUtil.showShortToast(mContext,"收藏失败");
                }
            });
        }
    

    最后在销毁Activity或Fragment时,要取消掉异步任务

    @Override
        protected void onDestroy() {
            super.onDestroy();
           if (addTask!=null&&!addTask.isCancelled()){
                addTask.cancel();
            }
        }
    

    注意:如果当Acitivity或Fragment被销毁时,在OnSuccess或OnError中执行UI操作,将导致程序奔溃 。
    用RealmAsyncTask .cancel();可以取消事务在onStop中调用,避免crash。

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

    (2)异步删

        private void deleteCat(final String id, final ImageView imageView){
          RealmAsyncTask  deleteTask=   mRealm.executeTransactionAsync(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                    Cat cat=realm.where(Cat.class).equalTo("id",id).findFirst();
                    cat.deleteFromRealm();
    
                }
            }, new Realm.Transaction.OnSuccess() {
                @Override
                public void onSuccess() {
                    ToastUtil.showShortToast(mContext,"取消收藏成功");
                }
            }, new Realm.Transaction.OnError() {
                @Override
                public void onError(Throwable error) {
                    ToastUtil.showShortToast(mContext,"取消收藏失败");
                }
            });
        }
    

    最后在销毁Activity或Fragment时,要取消掉异步任务

    @Override
        protected void onDestroy() {
            super.onDestroy();
           if (deleteTask!=null&&!addTask.isCancelled()){
                deleteTask.cancel();
            }
        }
    

    (3)异步改

    RealmAsyncTask  updateTask=   mRealm.executeTransactionAsync(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                    Cat cat=realm.where(Cat.class).equalTo("id",mId).findFirst();
                    cat.setName(name);
                }
            }, new Realm.Transaction.OnSuccess() {
                @Override
                public void onSuccess() {
                    ToastUtil.showShortToast(UpdateCatActivity.this,"更新成功");
                 
                }
            }, new Realm.Transaction.OnError() {
                @Override
                public void onError(Throwable error) {
                    ToastUtil.showShortToast(UpdateCatActivity.this,"失败成功");
                }
            });
    

    最后在销毁Activity或Fragment时,要取消掉异步任务

    @Override
        protected void onDestroy() {
            super.onDestroy();
           if (updateTask!=null&&!addTask.isCancelled()){
                updateTask.cancel();
            }
        }
    

    (4)异步查

         RealmResults<Cat>   cats=mRealm.where(Cat.class).findAllAsync();
            cats.addChangeListener(new RealmChangeListener<RealmResults<Cat>>() {
                @Override
                public void onChange(RealmResults<Cat> element) {
                   element= element.sort("id");
                    List<Cat> datas=mRealm.copyFromRealm(element);
                }
            });
    

    最后在销毁Activity或Fragment时,要取消掉异步任务

     @Override
        protected void onDestroy() {
            super.onDestroy();
            cats.removeChangeListeners();
        }
    

    十, 数据库数据更新监听

    MainActivity代码:

    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mRealm = Realm.getDefaultInstance();
            userDao = new UserDao(mRealm);
    
            //...
    
            /**
             * 数据库数据更新监听
             */
            mRealm.addChangeListener(this);
        }
    
    //...
    
    @Override
        public void onChange(Realm element) {
            findAll();
        }
    
    @Override
        protected void onDestroy() {
            userDao = null;
            mRealm.close();
            super.onDestroy();
        }
    

    十一, json转对象,插入数据库

    Realm还是个很nice的功能就是将Json字符串转化为对象,厉害了我的Realm
    (直接借用官方的例子)

    // 一个city model
    public class City extends RealmObject {
      private String city;
      private int id;
      // getters and setters left out ...
    }
    // 使用Json字符串插入数据
    realm.executeTransaction(new Realm.Transaction() {
      @Override
      public void execute(Realm realm) {
          realm.createObjectFromJson(City.class, "{ city: "Copenhagen", id: 1 }");
      }
    });
    // 使用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: * 该属性保持不变

    版本升级的问题,参考:http://www.jianshu.com/p/37af717761cc

    参照资料:
    http://www.jianshu.com/p/37af717761cc
    https://www.2cto.com/kf/201607/526365.html

  • 相关阅读:
    21.Merge Two Sorted Lists 、23. Merge k Sorted Lists
    34. Find First and Last Position of Element in Sorted Array
    leetcode 20. Valid Parentheses 、32. Longest Valid Parentheses 、301. Remove Invalid Parentheses
    31. Next Permutation
    17. Letter Combinations of a Phone Number
    android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事项
    oc 异常处理
    oc 类型判断
    oc Delegate
    oc 协议
  • 原文地址:https://www.cnblogs.com/neo-java/p/10185021.html
Copyright © 2011-2022 走看看