野狗 Sync 分析1 -数据监听(Android)

   2016-11-13 0
核心提示:数据监听方式比较Wilddog Sync 平台: AndroidWilddog Sync 版本: 2.0.1数据监听WilddogSync 提供了三种监听数据的方式:addListenerForSingleValueEvent(ValueEventListener listener)addValueEventListener(ValueEventListener listener)addChildEventList

数据监听方式比较

Wilddog Sync 平台: Android

Wilddog Sync 版本: 2.0.1

数据监听

WilddogSync 提供了三种监听数据的方式:

addListenerForSingleValueEvent(ValueEventListener listener)

addValueEventListener(ValueEventListener listener)

addChildEventListener(ChildEventListener listener)

addListenerForSingleValueEvent 主要用于一次性获取当前节点下数据的场景,触发一次后就会失效。

addValueEventListeneraddChildEventListener 都会为当前节点绑定监听事件,持续的监听当前节点数据的变化情况,那么,这三种方式有什么不同呢?

我们运行一下代码测试两种方式的差异。

测试代码如下:

//SyncReference reference = WilddogSync.getInstance().getReference();
        //设置ListenerForSingleValueEvent
        reference.child("listenerTest").addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                Log.e("single","onDataChange:"+dataSnapshot.toString());
            }

            @Override
            public void onCancelled(SyncError syncError) {
                Log.e("single",syncError.toString());
            }
        });
        //设置ValueEventListener
        reference.child("listenerTest").addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                Log.e("value",dataSnapshot.toString());
            }

            @Override
            public void onCancelled(SyncError syncError) {
                Log.e("value",syncError.toString());
            }
        });
        //设置ChildEventListener
        reference.child("listenerTest").addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                Log.e("child","added"+dataSnapshot.toString());
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                Log.e("child","changed"+dataSnapshot.toString());
            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {
                Log.e("child",dataSnapshot.toString());
            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onCancelled(SyncError syncError) {

            }
        });

获取数据

如果存在历史数据,运行上述代码,则会返回以下的数据:

Logcat日志:

//单次数据获取,addListenerForSingleValueEvent
E/single: onDataChange:DataSnapshot { key = listenerTest, value = {aaa=aaa, bbb={ccc=ccc}, ccc={ddd={eee=eee}}} }
//持续监听节点,addValueEventListener
E/value: onDataChange:DataSnapshot { key = listenerTest, value = {aaa=aaa, bbb={ccc=ccc}, ccc={ddd={eee=eee}}} }
//持续监听节点,addChildEventListener
E/child: onChildAdded:DataSnapshot { key = aaa, value = aaa }
E/child: onChildAdded:DataSnapshot { key = bbb, value = {ccc=ccc} }
E/child: onChildAdded:DataSnapshot { key = ccc, value = {ddd={eee=eee}} }

可以看出:

  • ValueListener会将当前节点下的数据一次性返回;
  • ChildListener将当前节点数据按子节点一个一个返回。

添加数据

当我们为某个节点添加了数据监听之后,就可以在客户端实时同步当前的数据。

现在我们考察一下为节点增加数据时,野狗实时数据同步的行为。

增加一个节点: {aaa=aaa}

E/child: onChildAdded : DataSnapshot { key = aaa, value = aaa }
E/value: onDataChange : DataSnapshot { key = listenerTest, value = {aaa=aaa} }

再增加一个同级节点: {bbb=bbb}

E/child: onChildAdded : DataSnapshot { key = bbb, value = bbb }
E/value: onDataChange : DataSnapshot { key = listenerTest, value = {aaa=aaa, bbb=bbb} }

增加一个带有子节点的节点ccc: {ccc={ddd=ddd}}

E/child: onChildAdded : DataSnapshot { key = ccc, value = {ddd=ddd} }
E/value: onDataChange : DataSnapshot { key = listenerTest, value = {aaa=aaa, bbb=bbb, ccc={ddd=ddd}} }

在ccc节点上增加子节点 {eee=eee}

E/child: onChildChanged : DataSnapshot { key = ccc, value = {ddd=ddd, eee=eee} }
E/value: onDataChange   : DataSnapshot { key = listenerTest, value = {aaa=aaa, bbb=bbb, ccc={ddd=ddd, eee=eee}} }

增加 {fff={ggg={hhh=hhh}}}

E/child: onChildAdded : DataSnapshot { key = fff, value = {ggg={hhh=hhh}} }
E/value: onDataChange : DataSnapshot { key = listenerTest, value = {aaa=aaa, fff={ggg={hhh=hhh}}, bbb=bbb, ccc={ddd=ddd, eee=eee}} }

增加 {fff={iii={jjj={kkk=kkk}}}}

E/child: onChildChanged : DataSnapshot { key = fff, value = {iii={jjj={kkk=kkk}}, ggg={hhh=hhh}} }
E/value: onDataChange   : DataSnapshot { key = listenerTest, value = {aaa=aaa, fff={iii={jjj={kkk=kkk}}, ggg={hhh=hhh}}, bbb=bbb, ccc={ddd=ddd, eee=eee}} }

总结:

1/ addValueEventListener 事件监听返回的 DataSnapshot 的 key 始终为当前节点,value 是当前节点变化后的全部字节点值;

addChildEventListener 事件监听的 key 是当前节点的下一级子节点,注意是下一级子节点,哪个下一级子节点的数据有了变化,key就是哪个子节点。

例如我们在 iii 节点下增加了 jjj 子节点,但是返回的数据依然是 DataSnapshot { key = fff, value = {iii={jjj={kkk=kkk}}, ggg={hhh=hhh}} } ,返回的是 listenerTest 下一级子节点 fff 节点的变化数据。

也就是说value事件关注当前节点的数据变化情况,返回的DataSnapshot中value是当前节点下所有数据的值;

child事件关注的是当前节点的子节点数据变化情况,返回的DataSnapshot中value是当前节点某个子节点所有数据的值。

2/value事件监听时,当前节点有数据增加则会触发onDataChange方法;

child事件监听时,增加下一级子节点时如子节点不存在则触发onChildAdded事件,如果子节点存在则触发onChildChanged事件。

删除数据

直接删除子节点,考察野狗实时数据同步的行为。

删除 aaa

此时 ChildEventListener 触发了 onChildRemoved 事件,返回的 valueaaa 节点被删除的数据。

E/child: onChildRemoved : DataSnapshot { key = aaa, value = aaa }
E/value: onDataChange   : DataSnapshot { key = listenerTest, value = {fff={iii={jjj={kkk=kkk}}, ggg={hhh=hhh}}, bbb=bbb, ccc={ddd=ddd, eee=eee}} }

删除 ddd

在执行删除操作前 ccc 节点下的数据为 ccc={ddd=ddd, eee=eee}} ,执行删除 ddd 节点之后, ccc 节点的数据变为 ccc={eee=eee}}

此时触发了 onChildChanged 事件,返回的值为当前 ccc 节点下的数据。

E/child: onChildChanged : DataSnapshot { key = ccc, value = {eee=eee} }
E/value: onDataChange   : DataSnapshot { key = listenerTest, value = {fff={iii={jjj={kkk=kkk}}, ggg={hhh=hhh}}, bbb=bbb, ccc={eee=eee}} }

删除 eee

再次触发了 onChildRemoved 事件,返回被删除的数据,此时整个 ccc 节点一同被删除。

E/child: onChildRemoved : DataSnapshot { key = ccc, value = {eee=eee} }
E/value: onDataChange   : DataSnapshot { key = listenerTest, value = {fff={iii={jjj={kkk=kkk}}, ggg={hhh=hhh}}, bbb=bbb} }

总结:

1/ addValueEventListener 事件监听始终返回被监听节点的数据;

addChildEventListener 事件监听返回的是变化的子节点的数据,根据不同情况触发不同监听。

2/删除节点时, ChildEventListener 会根据不同情形触发两个不同的事件:

事件 触发条件 结果
onChildRemoved 被删除节点的父节点只有一个子节点 返回被删除的节点数据
onChildChanged 被删除节点的父节点有多个子节点 返回变化后的被删除节点的父节点数据

3/删除节点时,如果被删除节点的父节点只有被删除节点这一个子节点,那么父节点会被同时删除。

应用实践

根据以上实验的结果,我们可以分析这两个不同监听的语义:

ValueEventListener 始终返回被监听节点的数据,所以 Value 指的是当前节点的值,也就是说,Value 关注当前节点值的变化情况。

ChildEventListener 始终返回被监听节点的下一级字节点的数据,那么 Child 指的是当前节点的下一级子节点,或者说直接子节点,其孙节点的变化一样会归为子节点的变化,关注的是当前节点下一级子节点变化情况。

需要注意的是,同一个路径可以重复设置监听,如果多次设置监听之后,每次数据变化都会触发每一个设置的监听,有可能多次处理相同业务,造成逻辑错误。

在一个监听已经失去继续保留的意义的时候,可以使用 removeEventListener() 方法移除不需要的监听。

 
标签: 安卓开发
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 安卓中通知功能的具体实现
    安卓中通知功能的具体实现
    通知[Notification]是Android中比较有特色的功能,当某个应用程序希望给用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助通知实现。使用通知的步骤1、需要一个NotificationManager来获得NotificationManager manager = (NotificationManager
    02-05 安卓开发
  • Android view系统分析-setContentView
    Android view系统分析-setContentView
    第一天上班,列了一下今年要学习的东西。主要就是深入学习Android相关的系统源代码,夯实基础。对于学习Android系统源代码,也没什么大概,就从我们平常使用最基础的东西学起,也就是从view这个切入点开始学习Android的源码,在没分析源码之前,我们有的时候
    02-05 安卓开发
  • 如何进行网络视频截图/获取视频的缩略图
    如何进行网络视频截图/获取视频的缩略图
    小编导读:获取视频的缩略图,截图正在播放的视频某一帧,是在音视频开发中,常遇到的问题。本文是主要用于点播中截图视频,同时还可以获取点播视频的缩略图进行显示,留下一个问题,如下图所示, 如果要获取直播中节目视频缩略图,该怎么做呢?(ps:直播是直
  • Android NDK 层发起 HTTP 请求的问题及解决
    Android NDK 层发起 HTTP 请求的问题及解决
    前言新的一年,大家新年快乐~~鸡年大吉!本次给大家带来何老师的最新文章~虽然何老师还在过节,但依然放心不下广大开发者,在此佳节还未结束之际,给大家带来最新的技术分享~ 事件的起因不说了,总之是需要实现一个 NDK 层的网络请求。为了多端适用,还是选择
  • Android插件化(六): OpenAtlasの改写aapt以防止资源ID冲突
    Android插件化(六): OpenAtlasの改写aapt以防
    引言Android应用程序的编译中,负责资源打包的是aapt,如果不对打包后的资源ID进行控制,就会导致插件中的资源ID冲突。所以,我们需要改写aapt的源码,以达到通过某种方式传递资源ID的Package ID,通过aapt打包时获取到这个Package ID并且应用才插件资源的命名
    02-05 安卓开发
  • Android架构(一)MVP架构在Android中的实践
    Android架构(一)MVP架构在Android中的实践
    为什么要重视程序的架构设计 对程序进行架构设计的原因,归根结底是为了 提高生产力 。通过设计是程序模块化,做到模块内部的 高聚合 和模块之间的 低耦合 (如依赖注入就是低耦合的集中体现)。 这样做的好处是使得程序开发过程中,开发人员主需要专注于一点,
    02-05 安卓开发
  • 安卓逆向系列教程 4.2 分析锁机软件
    安卓逆向系列教程 4.2 分析锁机软件
    安卓逆向系列教程 4.2 分析锁机软件 作者: 飞龙 这个教程中我们要分析一个锁机软件。像这种软件都比较简单,完全可以顺着入口看下去,但我这里还是用关键点来定位。首先这个软件的截图是这样,进入这个界面之后,除非退出模拟器,否则没办法回到桌面。上面那
    02-05 安卓开发
  • Android插件化(二):OpenAtlas插件安装过程分析
    Android插件化(二):OpenAtlas插件安装过程分析
    在前一篇博客 Android插件化(一):OpenAtlas架构以及实现原理概要 中,我们对应Android插件化存在的问题,实现原理,以及目前的实现方案进行了简单的叙述。从这篇开始,我们要深入到OpenAtlas的源码中进行插件安装过程的分析。 插件的安装分为3种:宿主启动时立
    02-05 安卓开发
  • [译] Android API 指南
    [译] Android API 指南
    众所周知,Android开发者有中文网站了,API 指南一眼看去最左侧的菜单都是中文,然而点进去内容还是很多是英文,并没有全部翻译,我这里整理了API 指南的目录,便于查看,如果之前还没有通读,现在可以好好看一遍。注意,如果标题带有英文,说明官方还没有翻
  • 使用FileProvider解决file:// URI引起的FileUriExposedException
    使用FileProvider解决file:// URI引起的FileUri
    问题以下是一段简单的代码,它调用系统的相机app来拍摄照片:void takePhoto(String cameraPhotoPath) {File cameraPhoto = new File(cameraPhotoPath);Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);takePhotoIntent.putExtra(Medi
    02-05 安卓开发
点击排行