title: 事件监听

事件监听是指通过事件触发的方式来获取云端变化的数据。通过监听云端事件,本地获取并处理数据,保持和数据实时同步。

事件

数据在云端发生变化后会触发事件。

事件包含以下五种:

事件类型 说明
onChildAdded() 初始化监听或有新增子节点。
onChildChanged() 子节点数据发生更改。
onChildRemoved() 子节点被删除。
onChildMoved() 子节点排序发生变化。
onDataChange() 初始化监听或向指定节点及子节点数据发生变化。

监听事件

通过 Wilddog Sync 提供的方法,监听云端的事件,保持和云端实时同步。

设置监听

onDataChange() 方法用于与事件配合来监听指定节点的数据。

例如,通过 onDataChange() 事件监听 Jobs 节点下的数据:

  1. ValueEventListener postListener = new ValueEventListener() {
  2. @Override
  3. public void onDataChange(DataSnapshot dataSnapshot) {
  4. String fullName = (String) snapshot.child("full_name").getValue();
  5. String gender = (String) snapshot.child("gender").getValue();
  6. System.out.println(fullName + " 性别为" + gender);
  7. // ...
  8. }
  9. @Override
  10. public void onCancelled(SyncError syncError) {
  11. // 获取数据失败,打印错误信息。
  12. Log.w(TAG, "loadPost:onCancelled", syncError.toString());
  13. // ...
  14. }
  15. };
  16. SyncReference postReference = mSyncRef.child("/web/saving-data/wildblog/users/Jobs");
  17. mPostReference.addValueEventListener(postListener);

之后 Jobs 节点下的数据发生任何变化,都会触发回调方法。

例如,博客应用 中,通过 Child 事件来监听博客的状态变化:

  1. // 获取 SyncReference 实例
  2. SyncReference ref = WilddogSync.getInstance().getReference("web/saving-data/wildblog/posts");
  3. // 设置监听
  4. ChildEventListener listener = ref.addChildEventListener(new ChildEventListener(){
  5. public void onChildAdded(DataSnapshot snapshot, String ref) {
  6. String author = (String) snapshot.child("author").getValue();
  7. String title = (String) snapshot.child("title").getValue();
  8. System.out.println(author + " 发布了一篇名为《" + title + "》的博客");
  9. }
  10. public void onChildChanged(DataSnapshot snapshot, String ref) {
  11. String author = (String) snapshot.child("author").getValue();
  12. String title = (String) snapshot.child("title").getValue();
  13. System.out.println(author + " 更新博客标题为《" + title + "》");
  14. }
  15. public void onChildMoved(DataSnapshot snapshot, String ref) {
  16. String author = (String) snapshot.child("author").getValue();
  17. String title = (String) snapshot.child("title").getValue();
  18. System.out.println("博客《" + title + "》被删除");
  19. }
  20. public void onChildRemoved(DataSnapshot snapshot) {
  21. }
  22. public void onCancelled(SyncError error) {
  23. }
  24. });

更详细的用法说明,请参考 API 文档

提示:

如果你只想监听一次数据,可使用addListenerForSingleValueEvent()方法。该监听的回调方法只被触发一次,之后会自动取消监听。

移除监听

removeEventListener() 方法用于移除指定事件。移除监听之后,事件回调方法将不会被触发。

参数为移除的事件类型和回调方法:

  1. // 获取 SyncReference 实例
  2. SyncReference ref = WilddogSync.getInstance().getReference("web/saving-data/wildblog/posts");
  3. // 移除监听
  4. ref.removeEventListener(listener);

注意:

在父节点上调用 removeEventListener() 时不会移除在其子节点上添加的监听。

条件监听

Wilddog Sync 支持对事件监听设置条件:数据排序或数据筛选。

根据数据排序监听

Wilddog Sync 支持按键(key)、按值(value)、按节点的优先级(priority) 或按指定子节点的值(value)对数据进行排序。

数据排序包含以下四种方法:

方法 说明
orderByChild() 按指定子节点的值(value)对结果排序。
orderByKey() 按节点的键(key)对结果排序。
orderByValue() 按节点的值(value)对结果排序。
orderByPriority() 按节点的优先级(priority)对结果排序。

orderByChild()

orderByChild()方法用于按子节点的指定值(value)对结果排序。

例如,在 班级示例应用 中按照每个学生的身高(”height” 节点的值)进行排序:

  1. // 初始化
  2. WilddogOptions wilddogOptions = new WilddogOptions.Builder().setSyncUrl("https://class-demo.wilddogio.com").build();
  3. WilddogApp.initializeApp(wilddogOptions);
  4. SyncReference ref = WilddogSync.getInstance().getReference("students");
  5. Query queryRef = ref.orderByChild("height");
  6. queryRef.addChildEventListener(new ChildEventListener() {
  7. public void onChildAdded(DataSnapshot snapshot, String ref) {
  8. String height = snapshot.child("height").getValue().toString();
  9. System.out.println(snapshot.getKey() + " was " + height + " centimeters tall");
  10. }
  11. public void onCancelled(SyncError arg0) {
  12. }
  13. public void onChildChanged(DataSnapshot arg0, String arg1) {
  14. }
  15. public void onChildMoved(DataSnapshot arg0, String arg1) {
  16. }
  17. public void onChildRemoved(DataSnapshot arg0) {
  18. }
  19. });

orderByKey()

orderByKey()方法用于按节点的键(key)对结果排序。

例如,在 班级示例应用 中按照学生的名称进行排序:

  1. WilddogOptions wilddogOptions = new WilddogOptions.Builder().setSyncUrl("https://class-demo.wilddogio.com").build();
  2. WilddogApp.initializeApp(wilddogOptions);
  3. SyncReference ref = WilddogSync.getInstance().getReference("students");
  4. Query queryRef = ref.orderByKey();
  5. queryRef.addChildEventListener(new ChildEventListener() {
  6. public void onChildAdded(DataSnapshot snapshot, String ref) {
  7. String height = snapshot.child("height").getValue().toString();
  8. System.out.println(snapshot.getKey());
  9. }
  10. public void onCancelled(SyncError arg0) {
  11. }
  12. public void onChildChanged(DataSnapshot arg0, String arg1) {
  13. }
  14. public void onChildMoved(DataSnapshot arg0, String arg1) {
  15. }
  16. public void onChildRemoved(DataSnapshot arg0) {
  17. }
  18. });

orderByValue()

orderByValue()方法用于按节点的值(value)对结果排序。

例如,在 得分示例应用 中按照得分数据进行排序:

  1. WilddogOptions wilddogOptions = new WilddogOptions.Builder().setSyncUrl("https://class-demo.wilddogio.com").build();
  2. WilddogApp.initializeApp(wilddogOptions);
  3. SyncReference ref = WilddogSync.getInstance().getReference("scores");
  4. Query queryRef = ref.orderByValue();
  5. queryRef.addChildEventListener(new ChildEventListener() {
  6. public void onChildAdded(DataSnapshot snapshot, String ref) {
  7. String height = snapshot.child("height").getValue().toString();
  8. System.out.println("The " + snapshot.getKey() + " student's score is " + snapshot.getValue());
  9. }
  10. public void onCancelled(SyncError arg0) {
  11. }
  12. public void onChildChanged(DataSnapshot arg0, String arg1) {
  13. }
  14. public void onChildMoved(DataSnapshot arg0, String arg1) {
  15. }
  16. public void onChildRemoved(DataSnapshot arg0) {
  17. }
  18. });

orderByPriority()

orderByPriority()方法用于按节点的优先级(priority)对结果排序。

注意:

  • 每次只能使用一种排序方法。对同一监听调用多个排序方法会引发错误。
  • 排序会占用较多计算机资源。如果你的应用使用了排序,建议定义 .indexOn规则,在服务器上添加索引以提高排序效率。详细请参考 添加索引

根据数据筛选结果监听

对数据排序之后,才能进行数据筛选。

数据筛选包含以下五种方法:

方法 用法
limitToFirst() 设置从第一条开始,一共返回多少个节点。
limitToLast() 设置从最后一条开始,一共返回多少个节点(返回结果仍是升序,降序要自己处理)。
startAt() 返回大于或等于指定的 key、value 或 priority 的节点,具体取决于所选的排序方法。
endAt() 返回小于或等于指定的 key、value 或 priority 的节点,具体取决于所选的排序方法。
equalTo() 返回等于指定的 key、value 或 priority 的节点,具体取决于所选的排序方法。可用于精确查询。

你可以结合不同的方法来筛选数据。例如,结合 startAt() 方法与 endAt() 方法将结果限制在指定的范围内。

数量筛选

limitToFirst()方法用于获取从第一条(或 startAt() 方法指定的位置)开始向后指定数量的子节点。

limitToLast()方法用于获取从最后一条(或 endAt() 方法指定的位置)开始向前指定数量的子节点。

例如,在 班级示例应用 中,如果你只想知道最高的是哪三位同学:

  1. SyncReference ref = WilddogSync.getInstance().getReference("students");
  2. Query queryRef = ref.orderByChild("height");
  3. queryRef.limitToLast(3).addChildEventListener(new ChildEventListener() {
  4. public void onChildAdded(DataSnapshot snapshot, String ref) {
  5. String height = snapshot.child("height").getValue().toString();
  6. System.out.println(snapshot.getKey() + " was " + height + " centimeters tall ");
  7. }
  8. public void onCancelled(SyncError arg0) {
  9. }
  10. public void onChildChanged(DataSnapshot arg0, String arg1) {
  11. }
  12. public void onChildMoved(DataSnapshot arg0, String arg1) {
  13. }
  14. public void onChildRemoved(DataSnapshot arg0) {
  15. }
  16. });

如果使用 limitToFirst(100) 筛选数据,那么第一次返回节点数最多为 100 个。当数据发生更改时,对于进入到前 100 个的节点,你会接收到 child_added 事件。对于从前 100 个中消失的节点,你会接收到 child_removed 事件。

范围筛选

startAt()方法、endAt()方法 和 equalTo() 方法用于监听选择任意起点、终点或等量点。

例如,在 班级示例应用 中,如果你只想知道哪些学生的考分超过 60:

  1. SyncReference ref = WilddogSync.getInstance().getReference("scores");
  2. Query queryRef = ref.orderByValue();
  3. queryRef.startAt(60).addChildEventListener(new ChildEventListener() {
  4. public void onChildAdded(DataSnapshot snapshot, String ref) {
  5. String score = snapshot.getValue().toString();
  6. System.out.println(snapshot.getKey() + " is " + score);
  7. }
  8. public void onCancelled(SyncError arg0) {
  9. }
  10. public void onChildChanged(DataSnapshot arg0, String arg1) {
  11. }
  12. public void onChildMoved(DataSnapshot arg0, String arg1) {
  13. }
  14. public void onChildRemoved(DataSnapshot arg0) {
  15. }
  16. });

注意:

范围筛选中,当节点的 value 相同时,会按照 key 进行排序。

范围筛选可用于 数据分页精确查询 。关于分页的具体实现,请参考 如何实现分页