元数据绑定系列(二):元数据绑定进阶 原创 精华
先上源码:
喵叔catuncle / TestMetaDataBinding(主程序)
喵叔catuncle / TestDataCenter(配合主程序演示跨进程、跨设备特性)
demo截图
![]() |
![]() |
---|---|
上一篇元数据绑定系列(一):元数据绑定的使用,算是元数据绑定入门。通过codelbs代码的学习,这一篇我们更深入思考一下。不然,对于元数据绑定我们永远只是停留在使用工具的重复劳动阶段。
代码项目结构
- entry:程序入口(主程序,自定义元数据类
HelloUiMetaData
也放在这个module) - dataability:请忽略这个名字,最开始放的是AlarmClock的数据绑定。后来rdb作为数据源要和dataability对比,所以也放在这个module里。
- datacenter:数据源相关的类
AlarmsDataAbility
和AlarmRdbStoreMetaDataHelper
以及数据库都放在这个module。为了体现数据绑定的ui层和数据层分离的思想,所以我刻意把数据层放在独立的Module中。 - mylibrary:放一些工具类
思考一:一个xml布局文件中可以使用多个元数据吗?
先说答案:可以。
核心代码:
demo中,我定义了两个元数据data
和helloUi
,都可以成功绑定。
实际开发中,如果一个页面中有多个业务上不同的区域,那么每个区域绑定的数据也必然是不同的。(如果强行定义在一个元数据实体中也可以,但是违背了“面向对象”的思想。)
详见 wang.unclecat.databinding.slice.HelloSlice
中示例
思考二:为什么Feature中使用 元数据绑定,Json Schema文件必须放在Entry的resource/rawfile.jsonschema
路径下?
否则报错提示"没有定义相应的schema"
反编译:
之前我总结过rawfile的使用,有这样的结论:
就算在myfeature这个module里
"resources/..."
也是"entry/resources/..."
的简写形式。
所以,Json Schema文件必须放在Entry中。可是,这显然不符合我们的开发习惯啊,我们应该把相关的资源放在同一个module里。
在本例中,dataability中使用的Json Schemaalarm_schema.json
是放在dataability这个module中,我是怎么做到的呢?
其实很简单
详见wang.unclecat.mylibrary.MetaDataFrameworkExtra
思考三:除了DataAbility作为数据源,还可以有其它形式的数据源吗?
codelabs中使用的元数据有如下三个:
MetaData
是所有元数据类的最终基类。
其中ClockRowMetaData
和CustomMetaData
都继承自DataAbilityMetaData
,而DataAbilityMetaData
的基类还是MetaData
,DataAbilityMetaData
以DataAbility为数据源。
NoteMetaData
通过自定义的class MyDataHandler implements CustomDao.ICustomMetaDataHandler
最终还是使用DataAbility作为数据源。
难道我们使用元数据绑定框架只能通过DataAbility来访问数据?
当然不是。
com.huawei.middleplatform:ohos-metadata-binding:1.0.0.0
中默认有三个MetaData
的子类
从名字上不难看出,它们本质只是数据源不同,用法上应该大同小异。
在 喵叔catuncle / TestMetaDataBinding中
-
我也会演示
RdbStoreMetaData
的用法,它以Rdb(关系型数据库)直接作为数据源,而不需要DataAbility中转。详见:wang.unclecat.dataability.alarm.metadata.ClockRowMetaData2
-
也会直接继承
MetaData
自定义我们的HelloUiMetaData
元数据类,它的数据源很简陋,只是内存中的一个变量。详见:wang.unclecat.databinding.HelloUiMetaData
-
至于
RemoteServiceMetaData
后续我会慢慢加上,先把这篇文章写完,不然放得时间太长了。
说了这么多,现在认真回答一下这个问题:除了DataAbility作为数据源,可以有Rdb、RemoteService、自定义数据源(这里可以根据自己的需求自由发挥)
思考四:关于RdbStoreMetaData
的问题一:
设置"rdbstore:///wang.unclecat.datacenter.AlarmRdbStoreMetaDataHelper"这样的uri会报错
如果把元数据数据绑定的日志开关打开,我们可以看到这样的error提示:
反编译:
发现boolean isIllegalDataUri(String var1)
有bug,解决方法就是跳过这个有bug的验证方法:
思考五:关于RdbStoreMetaData
的问题二
在使用RdbStoreMetaData
的过程中,我发现对rdb的操作只有查询是成功的,插入、删除、修改都失败。
反编译:
发现void notifyDataAdd(MetaData var1)
和void notifyDataDelete(MetaData var1)
是空实现,所以ui上插入、删除对MetaData的操作不会作用到数据层,也许是这个原因吧。当然,也有可能是我的用法不对。
ui上对MetaData的修改操作也同样不生效,我怀疑RdbStoreDao类中对MetaData没有调用addInnerObserver()
,这只是和DataAbilityDao的实现对比后的猜测。
思考六:自定义MetaData都有哪几种方法?
在demo中,目前我只是简单通过setCustomDao()
来设置自定义的SimpleDao
并实现SimpleDao.ISimpleMetaDataHandler
来完成对数据的绑定。
通过了解。自定义MetaData总结一下,有如下两种方法:
- 设置
SimpleDao
并实现相应的SimpleDao.ISimpleMetaDataHandler
- 设置
"datahandler:///com.huawei.metadatabindingdemo.custom_data_source.handler.MyDataHandler"
这样的uri,并实现相应的CustomDao.ICustomMetaDataHandler
//codelabs中有演示, 本示例代码中没有实现
思考七:抽象类MetaDataDao
的作用
此类封装了对数据源的直接操作(连接、增删改查等)。和常见的数据库orm框架中Dao的概念一致。
默认有五个实现类,前三个和内置的MetaData对应,后两个用于我们自定义MetaData
顺便看一下 MetaDataDaoHelper
的反编译结果:
可知MetaDataDao的实例化依赖uri的判断结果
思考八:跨进程、跨设备访问dataability类型的uri数据源
在同设备安装 喵叔catuncle / TestDataCenter(配合主程序演示跨进程、跨设备特性),使用体验上和本地访问dataability完全一致,本示例代码中已经实现。
理论上讲跨设备也应该是一样的,不过跨设备访问DataAbility会报如下的错。可是我已经注册了,并且本地(或本机跨进程)访问都是好的。
求大神指点跨设备访问DataAbility的方法!!!
求大神指点跨设备访问DataAbility的方法!!!
求大神指点跨设备访问DataAbility的方法!!!
思考九: 如何开启元数据绑定框架的日志
ohos.mp.metadata.binding.common.Log
是框架的日志工具类,默认是关闭的,开发过程中,我们可以打开,方法如下:
思考十:ui销毁之后,绑定关系需要解绑吗?
答案:需要,框架已自动完成,开发者无需干预。
还是反编译:
由上可知,框架会监听AbilitySlice的生命周期变化,并在其销毁时解绑
思考十一:元数据绑定的内部实现
上面那么多次反编译,我们也不难看出,元数据绑定基于APT(Annotation Processing Tool)即注解处理器。并且框架也由三部分组成(和ButterKinfe这类用到APT技术的框架一样):
- ohos-metadata-annotation定义注解
- ohos-metadata-processor注解处理器
- ohos-metadata-binding工具类
生成类似如下的文件:
思考十二:每个页面都对应一个DataAbility可以吗?
我的回答:可以,但是不建议这样做。
因为DataAbility
类似Android的ContentProvider,会跟着应用一起启动。如果有太多的DataAbility
会占用太多内存资源。那怎么使用元数据绑定的DataAbility
呢?
我们看官方文档是怎么介绍URI的:
- query:查询参数。
- fragment:可以用于指示要访问的子资源。
所以,我们只需要定义一个DataAbility,通过查询参数决定要访问的数据资源。
思考十三:绑定网络上的图片(绑定url)
codelabs里也有示例,通过自定义uioperate来实现。功能上和安卓的绑定适配器一样,都能达到扩展功能的目的。
关键代码:(有空我把使用示例也加到demo工程里)
思考十四:setRequestProperties
的bug
会报错:
报错原因:java: (String[])List.toArray() gives ClassCastException
修复方法:
很有连贯性呀,好帖支持下。
本来是一篇文章。考虑到难易程度。分成两篇,满足不同的读者。
有兴趣的朋友可以解决一下跨设备访问DataAbility的问题。以及有dataservice作为数据源的使用示例。
前排插眼
为啥你这么优秀,随便就能写出我看不懂的东西!
你看我的commit log,第一次提交是7月21。断断续续看了一个月的时间。中间也卡了好多次。不可能那么轻松写出来的。
不错啊
我在这里用不了这个标签啊
这个没关系。目前只是ide支持不太好。可以正常编译运行。