Realm数据库详细介绍

Realm数据库详细介绍

目录

0.官方简介

1.基本概念

2.使用方法流程

1.添加Realm到工程

2.创建一个Realm

3.创建一个RealmObject

4. 创建transaction

5.书写查询

3.实战演练

1.添加数据

2.查询数据

3.更新数据

4.删除数据

4.进阶用法

1.用json创建对象

2.数据模型改变的处理

3.与RxJava的结合

5.其他补充

1.在Application做初始化配置

2. RealmConfiguration类的说明翻译:

3.初始化数据

4.条件查询方法

6.其他介绍【异步操作 】

1.异步增

2.异步删

3.异步改

4.异步查

 

0.官方简介

    • Realm实例不能在不同的线程间访问操作。确切的说,你必须在每个要使用的线程上打开一个实例  每个线程都会使用引用计数来自动缓存Realm实例,所以只要引用计数不达到零,  调用getInstance(RealmConfiguration)方法将会返回缓存的Realm实例,应该算是一个轻量级的操作。
    • 对于UI线程来说,打开和关闭Realm实例,应当放在onCreate/onDestroy或者onStart/onStop方法中
    • 在不同的线程间,Realm实例使用Handler机制来调整他的状态。也就是说,Realm实例在线程中,如果没有Looper,是不能收到更新通知的。除非手动调用waitForChange()方法

1.基本概念

    • realm是一个跨平台移动数据库引擎,支持iOS、OS X(Objective-C和Swift)以及Android。
    • 因为是ORM,本身在设计时也针对移动设备(iOS、Android),所以非常简单易用,学习成本很低。
    • Realm是一个可以替代SQLite以及ORMlibraries的轻量级数据库。
    • 相比SQLite,Realm更快并且具有很多现代数据库的特性,比如支持JSON,流式api,数据变更通知,以及加密支持,这些都为安卓开发者带来了方便。

2.使用方法流程

1.添加Realm到工程

第一种方法

要在安卓工程中使用Realm,你需要在module的build.gradle文件中添加一个添加一个依赖:compile 'io.realm:realm-android:0.84.1'

第二种方法

在项目的build文件加上

buildscript {

 repositories {

     jcenter()

 }

 dependencies {

     ...

     classpath "io.realm:realm-gradle-plugin:1.2.0"

 }

 

在 app 的 build文件中加入

apply plugin: 'realm-android'

2.创建一个Realm

一个Realm相当于一个SQLite数据库。它有一个与之对应的文件,一旦创建将持久保存在安卓的文件系统中。

要创建一个新的Realm,你可以在任意Activity中调用静态方法Realm.getInstance。

Realm myRealm = Realm.getInstance(context);

注意,调用Realm.getInstance,而没有传入RealmConfiguration,会创建一个叫做 default.realm的Realm文件。

如果你想向app中添加另一个Realm,必须使用一个RealmConfiguration.Builder对象,并为 Realm file 指定一个独有的名字。

Realm myOtherRealm = Realm.getInstance(new RealmConfiguration.Builder(context).name("myOtherRealm.realm").build());

3.创建一个RealmObject

只要继承了RealmObject类,任意JavaBean都能存储在Realm中。不知道JavaBean是什么?它就是一个可序列化的java类,有默认构造器,成员变量有相应的getter/setter方法。比如,下面这个类的实例就能轻松的存储在一个Realm中:

public class Country extends RealmObject {

    private String name;

    private int population;

    public Country() { }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public int getPopulation() {

        return population;

    }

    public void setPopulation(int population) {

        this.population = population;

    }

}

 

多对多的关系

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

public class Email extends RealmObject {
    public String address;
    public boolean active;
}

如果你想让RealmObject的一个成员变量作为主键,你可以使用@PrimaryKey注解。比如,这里演示了如何为Country类添加一个主键code:

@PrimaryKey

private String code;

 

public String getCode() {

    return code;

}

 

public void setCode(String code) {

    this.code = code;

}

      • @PrimaryKey用来标识主键
      • 默认的所有的字段都会被存储
      • 如果某个字段不需要被存储到本地,则需在在这个字段上面加上@Ignore注解
      • @Index 为这个字段添加一个搜索引擎,这将使插入数据变慢、数据增大,但是查询会变快。建议在需要优化读取性能的情况下使用。

4. 创建transaction

虽然从一个Realm读取数据非常简单(下一节有讲),但是向它写入数据就稍微复杂一点。Realm遵循 ACID (数据库事务正确执行的四个基本要素的缩写)规范,为了确保原子性和一致性,它强制所有的写入操作都在一个事务中执行。

        • 开始一个新的事务,使用beginTransaction方法。
        • 结束这个事务,使用commitTransaction方法。

注:事务即英文里面的transaction

这里演示了如何创建和保存一个Country类的实例:

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

Realm myRealm = Realm.getDefaultInstance();

myRealm.beginTransaction();

Country country1 = myRealm.createObject(Country.class);

country1.setName("Norway");

country1.setPopulation(5165800);

country1.setCode("NO");

myRealm.commitTransaction();

你可能注意到了country1并不是用Country类的构造器创建的。对于一个Realm来说,管理一个RealmObject的实例,这个实例必须用createObject方法创建。

如果你必须使用构造器,别忘了在提交事务前使用相关Realm对象的copyToRealm方法。这里是示例:

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

Realm myRealm = Realm.getDefaultInstance();

Country country2 = new Country();

country2.setName("Russia");

country2.setPopulation(146430430);

country2.setCode("RU");

 

myRealm.beginTransaction();

Country copyOfCountry2 = myRealm.copyToRealm(country2);

myRealm.commitTransaction();

 

类型三:使用事物块

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);

            }

        });

5.书写查询

Realm为创建查询提供了一套非常直观和流式的API。要创建一个查询,使用相关Realm对象的where方法并传入你感兴趣的对象的类。创建完查询之后,你可以使用返回一个RealmResults对象的findAll方法获取所有的结果,findAll。

RealmResults<Country> results1 = myRealm.where(Country.class).findAll();

for(Country c:results1) {

Log.d("results1", c.getName());

}

Realm提供了几个命名非常贴切的方法,比如beginsWith, endsWith,lesserThan 和 greaterThan,可以用来过滤,筛选结果。

RealmResults<Country> results2 =myRealm.where(Country.class).greaterThan("population", 100000000).findAll();

如果你想查询结果被归类,你可以使用findAllSorted方法。在它的参数中,用一个String指定被归类field的名字,并用一个boolean指定归类顺序。

RealmResults<Country> results3 = myRealm.where(Country.class).findAllSorted("name", false);

3.实战演练

数据库的使用无非上就是增删改查这四种操作,其中查是重点,在写原生sql语句中这也是个难点。

1.添加数据

在用Realm进行操作之前需要对Realm作相关的配置操作,Realm中所有的写操作都必须在事务中进行,不然就会报错,记得在Activity的onDestory中调用realm.close()释放资源。

RealmConfiguration realmConfig = new RealmConfiguration.Builder(this).build();

Realm realm = Realm.getInstance(realmConfig);

 

 public void testAdd() {

        initRealm();

        realm.executeTransaction(new Realm.Transaction() {

            @Override

            public void execute(Realm realm) {

                for (int i = 0; i < 10; i++) {

                    User user = realm.createObject(User.class);

                    user.setName("user" + i);

                    user.setAge(10 + i);

                    user.setId(UUID.randomUUID().toString());

                }

                showInTextView("10条数据添加成功");

            }

        });

}

 

//记得一定要在onDestroy方法中释放资源, 否则会导致本地资源无法释放,引起OOM。

@Override

protected void onDestroy() {

    super.onDestroy();

    realm.close();

}

2.查询数据

查询全部

public void testQuery() {

      List<User> users= realm.where(User.class).findAll();

      for (User user: users) {

          showInTextView("id:" + user.getId() + " name:" + user.getName() + " age:" + user.getAge());

      }

}

条件查询,Realm 支持以下查询条件(来源于官网):

      • between()、greaterThan()、lessThan()、greaterThanOrEqualTo() 和 lessThanOrEqualTo()
      • equalTo() 和 notEqualTo()
      • contains()、beginsWith() 和 endsWith()
      • isNull() 和 isNotNull()
      • isEmpty() 和 isNotEmpty()

以下代码片段查询年龄小于15的User

public void testQueryAgeLessThan15() {

        List<User> users= realm.where(User.class).lessThan("age", 15).findAll();

        for (User user: users) {

            showInTextView("id:" + user.getId() + " name:" + user.getName() + " age:" + user.getAge());

        }

}

 

聚合查询,支持的聚合操作有sum,min,max,average

public void testQueryAverageAge() {

      double age = realm.where(User.class).findAll().average("age");

      textView.setText("average age:" + age);

}

3.更新数据

public void testUpdate() {

        realm.executeTransaction(new Realm.Transaction() {

            @Override

            public void execute(Realm realm) {

                User user = realm.where(User.class).equalTo("name", "user9").findFirst();

                if (user != null) {

                    user.setAge(99);

                    user.setName("二逼青年");

                }

                textView.setText("更新成功");

            }

        });

}

4.删除数据

以下代码片段展示了如何删除指定的对象

 public void testDelete() {

        realm.executeTransaction(new Realm.Transaction() {

            @Override

            public void execute(Realm realm) {

                User user = realm.where(User.class).equalTo("name", "user0").findFirst();

                if (user != null)

                    user.deleteFromRealm();

                textView.setText("删除成功");

            }

        });

}

4.进阶用法

1.用json创建对象

在实际开发中我们和json打交道的机会比较多,所以直接从json去创建对象是十分有用的,下面的代码片段展示了怎么去用。

private void testAddFromJson() {

        realm.executeTransaction(new Realm.Transaction() {

            @Override

            public void execute(Realm realm) {

                String json = "{\n" +

                        "    \"id\": \"uuid1\",\n" +

                        "    \"name\": \"solid\",\n" +

                        "    \"age\": 20\n" + "}";

                String jsons = "[\n" +

                        "    {\n" +

                        "        \"id\": \"uuid1\",\n" +

                        "        \"name\": \"solid\",\n" +

                        "        \"age\": 20\n" +

                        "    },\n" +

                        "    {\n" +

                        "        \"id\": \"uuid2\",\n" +

                        "        \"name\": \"jhack\",\n" +

                        "        \"age\": 21\n" +

                        "    },\n" +

                        "    {\n" +

                        "        \"id\": \"uuid3\",\n" +

                        "        \"name\": \"tom\",\n" +

                        "        \"age\": 22\n" +

                        "    }\n" +

                        "]";

                //realm.createObjectFromJson(User.class, json);

                realm.createAllFromJson(User.class, jsons);

            }

        });

}

2.数据模型改变的处理

开发中数据模型不可能从一开始创建了,就保证后面的开发过程中不会更改,对于Realm如果其中的某个实体类改变了,而我们没有做任何的处理,就会报错,如果还处于应用的开发的初期,这无所谓,直接清空数据即可,但是如果应用已经发布了,我们就需要去寻找一种解决方案了。

public class MyMigration implements RealmMigration {

    @Override

    public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {

        Log.e(MainActivity.TAG, "oldVersion:" + oldVersion + " newVersion:" + newVersion);

 

        RealmSchema schema = realm.getSchema();

 

        if (newVersion == 2) {

            schema.get("User")

                    .addField("desc", String.class);

        }

    }

 

    @Override

    public boolean equals(Object obj) {

        return obj instanceof MyMigration;

    }

 

    @Override

    public int hashCode() {

        return super.hashCode();

    }

}

 

realmConfig = new RealmConfiguration

                .Builder(this)

                .schemaVersion(2)

                .migration(new MyMigration())

                .build();

3.与RxJava的结合

Realm原生是支持Rxjava的,由于RxJava 是可选依赖,所以在使用的时候需要在app的build文件中添加RxJava库的依赖,下面是使用的代码片段。

public void testRxJava() {

        realm.where(User.class).findAll()

                .asObservable()

                .flatMap(new Func1<RealmResults<User>, Observable<User>>() {

                    @Override

                    public Observable<User> call(RealmResults<User> users) {

                        return Observable.from(users);

                    }

                })

                .subscribe(new Action1<User>() {

                    @Override

                    public void call(User user) {

                        showInTextView("id:" + user.getId() + " name:" + user.getName() + " age:" + user.getAge() + " desc:" + user.getDesc());

 

                    }

                });

}

5.其他补充

1.在Application做初始化配置

1.使用默认配置

RealmConfiguration realmConfig = new RealmConfiguration.Builder(this).build();

Realm.setDefaultConfiguration(realmConfig);

 

2.使用自定义配置

RealmConfiguration config = new  RealmConfiguration.Builder(this)

        .name("myRealm.realm")

        .deleteRealmIfMigrationNeeded()

        .build();

Realm.setDefaultConfiguration(config);

 

3.记得到清单文件配置

<application

  android:name=".MyApplication"

  ...

/>

2. RealmConfiguration类的说明翻译:

/**

* 一个RealmConfiguration对象,可用来设置特定的Realm实例

* RealmConfiguration实例只能通过io.realm.RealmConfiguration.Builder类的build()方法来创建

* 想使用默认的RealmConfiguration实例,请使用io.realm.Realm#getDefaultInstance()方法。

* 如果想使用自己配置RealmConfiguration实例的Realm实例,需要调用Realm#setDefaultConfiguration(RealmConfiguration)

*

* <p>

* 可以用下面代码创建一个最简单配置的实例:

* RealmConfiguration config = new RealmConfiguration.Builder(getContext()).build())

* 这样创建的实例,具有一下属性:

*

* <ul>

* <li>Realm的默认文件名是"default.realm"</li>

* <li>"default.realm"文件保存在"Context.getFilesDir()"目录中</li>

* <li>它的schema版本号设置为0</li>

* </ul>

*/

 

解释:  

             1.即默认文件目录:/data/data/<packagename>/files/default.realm。意思是,当你在应用管理里面给当前app"清除数据",realm数据库的数据会丢失。

   2.可以设置默认文件名,通过RealmConfiguration类进行配置。路径似乎改不了,需要看具体设备供应商的实现。

   3. Realm的实例需要在每次的具体操作中获取,可以看成是一个数据操作的sessin,用完后必须close关闭。

   4. 重点:切记,Realm数据库的主键字段不是自动增长的,需要自己设置,做添加的时候如果不给id字段值,默认会为0。

   5. 数据自动更新。mRealm.addChangeListener(this);//当数据库的数据有变化时,系统回调此方法。

 

3.初始化数据

//init data 

public boolean init() { 

    /** 

     * 此处要注意,方法最后调用的是添加或者修改的方法。 

     * 如果list的数据都不给id,则第一条记录添加成功后的id为0,后面的都在此基础上修改。 

     * 最后的效果是,数据库只有一条记录,id为0,其他字段被更新为了最后一个对象的数据 

     */ 

    List<TestUser> list = new ArrayList<>(); 

    list.add(new TestUser(0,"android", "123123", 20, "河南常德", "传菜员", "女")); 

    list.add(new TestUser(1,"angel", "13588889988", 21, "云南西双版纳", "飞行员", "男")); 

    list.add(new TestUser(2,"adidass", "110119", 28, "云南德克萨斯州", "海员", "男")); 

    list.add(new TestUser(3,"hijack", "250250", 39, "加州电厂", "厨师", "女")); 

    list.add(new TestUser(4,"hibrid", "120250", 26, "赣州", "贼", "男")); 

    list.add(new TestUser(5,"admin", "123456", 20, "湖北汉城", "程序员", "女")); 

    return saveOrUpdateBatch(list); 

4.条件查询方法

/** 

 * 条件查询 

 * 

 * @return 返回结果集合 

 */ 

public RealmResults<TestUser> findByAnyParams(HashMap<Object, Object> params) { 

    //realm.where(TestUser.class) 

    //可跟查询条件 

    //.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()                     求和 

    return realm.where(TestUser.class).findAll(); 

 

6.其他介绍

异步操作

 

大多数情况下,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();

        }

    }

 

(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();

 

    }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://my.oschina.net/zbj1618/blog/847980

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值