精华内容
下载资源
问答
  • 本文着眼于煤炭资源资本化绿色发展的核心内容,并利用ROSTCM6和UCINET软件以“凝聚子群”的方法构建了煤炭资源资本化绿色理论的六个框架:资本化的基本理论。 ,资本化的保护理论,环境保护的资本化理论,资本化的...
  • 基于“全评价”理论框架的开放存取仓储评价体系的构建,陈铭,叶继元,开放存取仓储发展迅速,为了明确哪些是高质量的开放存取仓储,以便用户有效的利用开放存取仓储。该文从
  • 并从补偿原则、补偿主客体、补偿标准及补偿模式等四个方面完善农田生态补偿的结构框架。同时,以土地利用为视角构建农田生态补偿的测算体系,并论证了根据区域经济发展水平与农田生态系统服务价值的关系法测算经济...
  • 构建《学习与成才系统心理学》理论体系框架,韩忠,, 本文应用系统科学方法首先分别构建了学习心理素质结构系统和成才心理素质结构系统的时空结构模型,通过研究组成两个系统的各个心�
  • 基于扎根理论的“互联网 健康医疗”框架构建.pdf
  • 为了构建公路景观设计理论框架,通过探讨公路景观设计理论涵义提出,公路景观的研究框架应该包括公路景观设计原理、景观设计理论框架构成以及从中提取的景观设计指标。
  • 构建《学本素质教育学》“双层次结构”基本理论体系框架,韩忠,,本文首先应用系统科学方法构建了学习系统的时空结构模型,通过分析学习系统中各子系统之间的相互作用与相互联系和学习系统与外部
  • 研究首先从资源基础、发展能力、战略选取等方面区分创业型企业与成熟企业不同组织特征,在PPM理论框架下,结合创业型企业迁徙行为特点,从推力、拉力与调节3个方面构建了创业企业迁徙行为影响因素的理论模型。...
  • 从内部控制实施的角度出发,探讨信息技术能力对内部控制作用,认为信息技术能力从制度层面、流程层面以及信息层面对内部控制产生了积极的效果,同时构建了信息技术能力对内部控制作用的研究框架,以期为以后的研究提供...
  • 《中国制造2025》明确了制造强国路线图。经济发展新常态下,我国制造业共性技术研发在知识经济背景下需要新的理论指导实践。...构建理论框架模型,以期对新常态下我国制造业的共性技术研发及产业转型升级提供借鉴。
  • 引入交通环境容量和交通环境承载力概念,建立了城市交通环境承载力模型,构建了城市生态交通规划的理论框架。研究表明,该理论框架充分考虑了交通环境承载力和交通发展的相互作用,通过确定合理的交通结构和土地利用模式...
  • 开放的复杂巨系统及其方法论——综合集成研讨厅体系的提出,使得我们对复杂性的研究方向有了一个清晰的把握。同时,该方法论又是思维科学的一项...本文阐述了作者在综合集成研讨厅的理论框架、设计与实现方面的工作。
  • 本文以契约理论为切入点对企业逃税行为进行分析,通过在企业所有者和经营者合谋逃税活动中引入线性激励的“可自我执行的协议”,构建了一个逃税模型来研究企业逃税主体的决策行为。结果表明:经理人风险态度、逃税...
  • 我们检查了先前的研究如何将情境纳入理论中,并开发了一个框架来对现有的情境化方法进行分类。 此外,我们阐述了一种分解上下文的方法,并提出了一套开发特定于上下文的模型的指南。 我们通过构建和比较技术接受...
  • 国有企业内部控制与风险预警机制...表性成果 这些成果是理论研究应用于实务的桥梁 对内部控制实务产生了 重大影响 美国 英国和我国相关准则所确立的现代企业内部控制框架以及 代表性的理论框架对国有企业内部控制与风险
  • 基于社区理论,从层次结构,功能结构,运行结构和内容结构四个方面提出了省级终身教育社区的总体结构,并解释了终身教育实体社区三个支撑体系的总体结构。 ,学习平台和资源社区以及学习成绩认证和转换社区。 在探索...
  • 构建自己的知识体系框架

    千次阅读 2018-01-23 21:32:48
    第四课:构建自己的知识框架1、为什么要建立知识框架(一定要有框架意识) 便于提取 便于分享 便于记忆 2、一般性的学习误区 只收藏,不阅读 只阅读,不归类 只归类,不提炼 3、框架思维下的学习步骤 第一步——收集...

    第四课:构建自己的知识框架

    1、为什么要建立知识框架(一定要有框架意识)

    • 便于提取
    • 便于分享
    • 便于记忆

    2、一般性的学习误区

    • 只收藏,不阅读
    • 只阅读,不归类
    • 只归类,不提炼

    3、框架思维下的学习步骤

    • 第一步——收集
    • 第二步——整理
    • 第三步——消化
    • 第四步——输出

    一般性学习只有第一步,没有后面三个步骤


    第一步——收集

    • 收集工具:发送至印象笔记;备忘录
    • 收集途径:从喜爱的做着或者感兴趣的话题出发,形成一个舒适的学习路径

    第二步——整理

    • 整理目标:形成秩序;形成关联
    • 整理工具:标签和思维导图
    • 另外整理学到的东西,也可以利用博客,写出来既可以加深自己的印象,又可以分享给他人,给别人提供借鉴。

    第四步——输出

    • 输出方式——写作(或者与人讲解)
    • 倒逼自己去完善知识框架
    • 检验自己对于知识框架的掌握和理解

    4、思维框架

    成为更有秩序和更聪明的人

    做事之前,先从框架上考虑做事的步骤和方面

    做事之后,再从框架上去提炼思维和理论

    对于知识的整理,消化和提炼是非常重要的几个步骤,因为平时我们利用碎片化学习到的东西可能过段时间就会被其他东西冲掉,所以在我们学习到一些东西以后就要抓紧把那些细碎的东西记录下来进行整理,再思考,这也就是消化和加深印象的过程。

    知识就是在一点一点的积累才会变得越来越丰富,其实,如今我们每天都可以从手机上,电脑上接收到海量的数据与知识,如果我们能够每天对这些学到的关键性的东西进行收集整理,会发现长此以往,自身就会有变化。无论是谈吐上,还是举止上

    展开全文
  • 赫尔德对当今的全球化理论进行了系统的分类,在此基础上,赫尔德从变革论的立场出发,构建出了一个精致的全球化理论分析框架。赫尔德的全球化理论分析框架提出以来,受到学术界的广泛重视,它为人们分析当代全球化的历史...
  • 伴随建立和谐社会、法制社会的进程,对法务会计的研究...文章分析了构建法务会计体系的必要性,借鉴财务会计体系框架构建,从目标与对象、假设与原则、会计程序、会计报告等方面探讨了我国法务会计体系框架的具体构建
  • 自然资源资产负债表编制框架构建研究,周志方,王玉,自然资源资产负债表是加强我国生态文明建设的制度创新。然而目前我国缺乏足够的理论和实践研究,面临着自然资源统计复杂、资源资
  • 论堤防项目后评价指标体系框架构建,周亚东,,从堤防工程项目管理的角度出发,在科学发展观的指导下,结合后评价的基本理论,提出构建堤防项目后评价指标体系的框架
  • 如何构建Android MVVM 应用框架

    千次阅读 2016-11-11 20:38:00
    MVVM是一种架构模式,而DataBinding是一个实现数据和UI绑定的框架,是构建MVVM模式的一个工具。 之前看过很多关于Android MVVM的博客,但大多数提到的都是DataBinding的基本用法,很少有文章仔细讲解在A...

    概述

    说到Android MVVM,相信大家都会想到Google 2015年推出的DataBinding框架。然而两者的概念是不一样的,不能混为一谈。MVVM是一种架构模式,而DataBinding是一个实现数据和UI绑定的框架,是构建MVVM模式的一个工具。

    之前看过很多关于Android MVVM的博客,但大多数提到的都是DataBinding的基本用法,很少有文章仔细讲解在Android中是如何通过DataBinding去构建MVVM的应用框架的。View、ViewModel、Model每一层的职责如何?它们之间联系怎样、分工如何、代码应该如何设计?这是我写这篇文章的初衷。

    接下来,我们先来看看什么是MVVM,然后再一步一步来设计整个MVVM框架。

    MVC、MVP、MVVM

    首先,我们先大致了解下Android开发中常见的模式。

    MVC

    View:XML布局文件。
    Model:实体模型(数据的获取、存储、数据状态变化)。
    Controller:对应于Activity,处理数据、业务和UI。

    从上面这个结构来看,Android本身的设计还是符合MVC架构的,但是Android中纯粹作为View的XML视图功能太弱,我们大量处理View的逻辑只能写在Activity中,这样Activity就充当了View和Controller两个角色,直接导致Activity中的代码大爆炸。相信大多数Android开发者都遇到过一个Acitivty数以千行的代码情况吧!所以,更贴切的说法是,这个MVC结构最终其实只是一个Model-View(Activity:View&Controller)的结构。

    MVP

    View: 对应于Activity和XML,负责View的绘制以及与用户的交互。
    Model: 依然是实体模型。
    Presenter: 负责完成View与Model间的交互和业务逻辑。

    前面我们说,Activity充当了View和Controller两个角色,MVP就能很好地解决这个问题,其核心理念是通过一个抽象的View接口(不是真正的View层)将Presenter与真正的View层进行解耦。Persenter持有该View接口,对该接口进行操作,而不是直接操作View层。这样就可以把视图操作和业务逻辑解耦,从而让Activity成为真正的View层。

    但MVP也存在一些弊端:

    • Presenter(以下简称P)层与View(以下简称V)层是通过接口进行交互的,接口粒度不好控制。粒度太小,就会存在大量接口的情况,使代码太过碎版化;粒度太大,解耦效果不好。同时对于UI的输入和数据的变化,需要手动调用V层或者P层相关的接口,相对来说缺乏自动性、监听性。如果数据的变化能自动响应到UI、UI的输入能自动更新到数据,那该多好!
    • MVP是以UI为驱动的模型,更新UI都需要保证能获取到控件的引用,同时更新UI的时候要考虑当前是否是UI线程,也要考虑Activity的生命周期(是否已经销毁等)。
    • MVP是以UI和事件为驱动的传统模型,数据都是被动地通过UI控件做展示,但是由于数据的时变性,我们更希望数据能转被动为主动,希望数据能更有活性,由数据来驱动UI。
    • V层与P层还是有一定的耦合度。一旦V层某个UI元素更改,那么对应的接口就必须得改,数据如何映射到UI上、事件监听接口这些都需要转变,牵一发而动全身。如果这一层也能解耦就更好了。
    • 复杂的业务同时也可能会导致P层太大,代码臃肿的问题依然不能解决。

    MVVM

    View: 对应于Activity和XML,负责View的绘制以及与用户交互。
    Model: 实体模型。
    ViewModel: 负责完成View与Model间的交互,负责业务逻辑。

    MVVM的目标和思想与MVP类似,利用数据绑定(Data Binding)、依赖属性(Dependency Property)、命令(Command)、路由事件(Routed Event)等新特性,打造了一个更加灵活高效的架构。

    数据驱动

    在常规的开发模式中,数据变化需要更新UI的时候,需要先获取UI控件的引用,然后再更新UI。获取用户的输入和操作也需要通过UI控件的引用。在MVVM中,这些都是通过数据驱动来自动完成的,数据变化后会自动更新UI,UI的改变也能自动反馈到数据层,数据成为主导因素。这样MVVM层在业务逻辑处理中只要关心数据,不需要直接和UI打交道,在业务处理过程中简单方便很多。

    低耦合度

    MVVM模式中,数据是独立于UI的。

    数据和业务逻辑处于一个独立的ViewModel中,ViewModel只需要关注数据和业务逻辑,不需要和UI或者控件打交道。UI想怎么处理数据都由UI自己决定,ViewModel不涉及任何和UI相关的事,也不持有UI控件的引用。即便是控件改变了(比如:TextView换成EditText),ViewModel也几乎不需要更改任何代码。它非常完美的解耦了View层和ViewModel,解决了上面我们所说的MVP的痛点。

    更新UI

    在MVVM中,数据发生变化后,我们在工作线程直接修改(在数据是线程安全的情况下)ViewModel的数据即可,不用再考虑要切到主线程更新UI了,这些事情相关框架都帮我们做了。

    团队协作

    MVVM的分工是非常明显的,由于View和ViewModel之间是松散耦合的:一个是处理业务和数据、一个是专门的UI处理。所以,完全由两个人分工来做,一个做UI(XML和Activity)一个写ViewModel,效率更高。

    可复用性

    一个ViewModel可以复用到多个View中。同样的一份数据,可以提供给不同的UI去做展示。对于版本迭代中频繁的UI改动,更新或新增一套View即可。如果想在UI上做A/B Testing,那MVVM是你不二选择。

    单元测试

    有些同学一看到单元测试,可能脑袋都大。是啊,写成一团浆糊的代码怎么可能做单元测试?如果你们以代码太烂无法写单元测试而逃避,那可真是不好的消息了。这时候,你需要MVVM来拯救。

    我们前面说过了,ViewModel层做的事是数据处理和业务逻辑,View层中关注的是UI,两者完全没有依赖。不管是UI的单元测试还是业务逻辑的单元测试,都是低耦合的。在MVVM中数据是直接绑定到UI控件上的(部分数据是可以直接反映出UI上的内容),那么我们就可以直接通过修改绑定的数据源来间接做一些Android UI上的测试。

    通过上面的简述以及模式的对比,我们可以发现MVVM的优势还是非常明显的。虽然目前Android开发中可能真正在使用MVVM的很少,但是值得我们去做一些探讨和调研。

    如何构建MVVM应用框架

    如何分工

    构建MVVM框架首先要具体了解各个模块的分工。接下来我们来讲解View、ViewModel、Model它们各自的职责所在。

    View

    View层做的就是和UI相关的工作,我们只在XML、Activity和Fragment写View层的代码,View层不做和业务相关的事,也就是我们在Activity不写业务逻辑和业务数据相关的代码,更新UI通过数据绑定实现,尽量在ViewModel里面做(更新绑定的数据源即可),Activity要做的事就是初始化一些控件(如控件的颜色,添加RecyclerView的分割线),View层可以提供更新UI的接口(但是我们更倾向所有的UI元素都是通过数据来驱动更改UI),View层可以处理事件(但是我们更希望UI事件通过Command来绑定)。简单地说:View层不做任何业务逻辑、不涉及操作数据、不处理数据,UI和数据严格的分开。

    ViewModel

    ViewModel层做的事情刚好和View层相反,ViewModel只做和业务逻辑和业务数据相关的事,不做任何和UI相关的事情,ViewModel 层不会持有任何控件的引用,更不会在ViewModel中通过UI控件的引用去做更新UI的事情。ViewModel就是专注于业务的逻辑处理,做的事情也都只是对数据的操作(这些数据绑定在相应的控件上会自动去更改UI)。同时DataBinding框架已经支持双向绑定,让我们可以通过双向绑定获取View层反馈给ViewModel层的数据,并对这些数据上进行操作。关于对UI控件事件的处理,我们也希望能把这些事件处理绑定到控件上,并把这些事件的处理统一化,为此我们通过BindingAdapter对一些常用的事件做了封装,把一个个事件封装成一个个Command,对于每个事件我们用一个ReplyCommand去处理就行了,ReplyCommand会把你可能需要的数据带给你,这使得我们在ViewModel层处理事件的时候只需要关心处理数据就行了,具体见MVVM Light Toolkit 使用指南的Command部分。再强调一遍:ViewModel 不做和UI相关的事。

    Model

    Model层最大的特点是被赋予了数据获取的职责,与我们平常Model层只定义实体对象的行为截然不同。实例中,数据的获取、存储、数据状态变化都是Model层的任务。Model包括实体模型(Bean)、Retrofit的Service ,获取网络数据接口,本地存储(增删改查)接口,数据变化监听等。Model提供数据获取接口供ViewModel调用,经数据转换和操作并最终映射绑定到View层某个UI元素的属性上。

    如何协作

    关于协作,我们先来看下面的一张图:

    图 1

    上图反映了MVVM框架中各个模块的联系和数据流的走向,我们从每个模块一一拆分来看。那么我们重点就是下面的三个协作。

    • ViewModel与View的协作
    • ViewModel与Model的协作
    • ViewModel与ViewModel的协作

    ViewModel与View的协作

    图 2

    图2中ViewModel和View是通过绑定的方式连接在一起的,绑定分成两种:一种是数据绑定,一种是命令绑定。数据的绑定DataBinding已经提供好了,简单地定义一些ObservableField就能把数据和控件绑定在一起了(如TextView的text属性),但是DataBinding框架提供的不够全面,比如说如何让一个URL绑定到一个ImageView,让这个ImageView能自动去加载url指定的图片,如何把数据源和布局模板绑定到一个ListView,让ListView可以不需要去写Adapter和ViewHolder相关的东西?这些就需要我们做一些工作和简单的封装。MVVM Light Toolkit 已经帮我们做了一部分的工作,详情可以查看MVVM Light Toolkit 使用指南。关于事件绑定也是一样,MVVM Light Toolkit 做了简单的封装,对于每个事件我们用一个ReplyCommand去处理就行了,ReplyCommand会把可能需要的数据带给你,这样我们处理事件的时候也只关心处理数据就行了。

    图 1 中ViewModel的模块中我们可以看出ViewModel类下面一般包含下面5个部分:

    • Context (上下文)
    • Model (数据源 Java Bean)
    • Data Field (数据绑定)
    • Command (命令绑定)
    • Child ViewModel (子ViewModel)

    我们先来看下示例代码,然后再一一讲解5个部分是干嘛用的:

    //context
    private Activity context;
    
    //model(数据源 Java Bean)
    private NewsService.News news;
    private TopNewsService.News topNews;
    
    //数据绑定,绑定到UI的字段(data field)
    public final ObservableField<String> imageUrl = new ObservableField<>();
    public final ObservableField<String> html = new ObservableField<>();
    public final ObservableField<String> title = new ObservableField<>();
    // 一个变量包含了所有关于View Style 相关的字段
    public final ViewStyle viewStyle = new ViewStyle();
    
    
    //命令绑定(command)
    public final ReplyCommand onRefreshCommand = new ReplyCommand<>(() -> {    
    
    })
    public final ReplyCommand<Integer> onLoadMoreCommand = new ReplyCommand<>((itemCount) -> { 
    
    });
    
    
    //Child ViewModel
    public final ObservableList<NewItemViewModel> itemViewModel = new ObservableArrayList<>();
    
    /** * ViewStyle 关于控件的一些属性和业务数据无关的Style 可以做一个包裹,这样代码比较美观,
    ViewModel 页面也不会有太多太杂的字段。 **/
    public static class ViewStyle {    
       public final ObservableBoolean isRefreshing = new ObservableBoolean(true);    
       public final ObservableBoolean progressRefreshing = new ObservableBoolean(true);
    }
    

    Context

    Context是干嘛用的呢,为什么每个ViewModel都最好需要持了一个Context的引用呢?ViewModel不处理和UI相关的事也不操作控件,更不更新UI,那为什么要有Context呢?原因主要有以下两点:

    1. 通过图1中,然后得到一个Observable,其实这就是网络请求部分。其实这就是网络请求部分,做网络请求我们必须把Retrofit Service返回的Observable绑定到Context的生命周期上,防止在请求回来时Activity已经销毁等异常,其实这个Context的目的就是把网络请求绑定到当前页面的生命周期中。

    2. 在图1中,我们可以看到两个ViewModel之间的联系是通过Messenger来做,这个Messenger是需要用到Context,这个我们后续会讲解。

    当然,除此以外,调用工具类、帮助类有时候需要Context做为参数等也是原因之一。

    Model (数据源)

    Model是什么呢?其实就是数据源,可以简单理解是我们用JSON转过来的Bean。ViewModel要把数据映射到UI中可能需要大量对Model的数据拷贝和操作,拿Model的字段去生成对应的ObservableField然后绑定到UI(我们不会直接拿Model的数据去做绑定展示),这里是有必要在一个ViewModel保留原始的Model引用,这对于我们是非常有用的,因为可能用户的某些操作和输入需要我们去改变数据源,可能我们需要把一个Bean在列表页点击后传给详情页,可能我们需要把这个Model当做表单提交到服务器。这些都需要我们的ViewModel持有相应的Model(数据源)。

    Data Field(数据绑定)

    Data Field就是需要绑定到控件上的ObservableField字段,这是ViewModel的必需品,这个没有什么好说。但是这边有一个建议:
    这些字段是可以稍微做一下分类和包裹的。比如说可能一些字段是绑定到控件的一些Style属性上(如长度、颜色、大小),对于这类针对View Style的的字段可以声明一个ViewStyle类包裹起来,这样整个代码逻辑会更清晰一些,不然ViewModel里面可能字段泛滥,不易管理和阅读性较差。而对于其他一些字段,比如说title、imageUrl、name这些属于数据源类型的字段,这些字段也叫数据字段,是和业务数据和逻辑息息相关的,这些字段可以放在一块。

    Command(命令绑定)

    Command(命令绑定)简言之就是对事件的处理(下拉刷新、加载更多、点击、滑动等事件处理)。我们之前处理事件是拿到UI控件的引用,然后设置Listener,这些Listener其实就是Command。但是考虑到在一个ViewModel写各种Listener并不美观,可能实现一个Listener就需要实现多个方法,但是我们可能只想要其中一个有用的方法实现就好了。更重要一点是实现一个Listener可能需要写一些UI逻辑才能最终获取我们想要的。简单举个例子,比如你想要监听ListView滑到最底部然后触发加载更多的事件,这时候就要在ViewModel里面写一个OnScrollListener,然后在里面的onScroll方法中做计算,计算什么时候ListView滑动底部了。其实ViewModel的工作并不想去处理这些事件,它专注做的应该是业务逻辑和数据处理,如果有一个东西不需要你自己去计算是否滑到底部,而是在滑动底部自动触发一个Command,同时把当前列表的总共的item数量返回给你,方便你通过 page=itemCount/LIMIT+1去计算出应该请求服务器哪一页的数据那该多好啊。MVVM Light Toolkit 帮你实现了这一点:

     public final ReplyCommand<Integer> onLoadMoreCommand =  new ReplyCommand<>((itemCount) -> { 
       int page=itemCount/LIMIT+1; 
       loadData(page.LIMIT)
    });
    

    接着在XML布局文件中通过bind:onLoadMoreCommand绑定上去就行了。

     <android.support.v7.widget.RecyclerView 
     android:layout_width="match_parent"  
     android:layout_height="match_parent"  
     bind:onLoadMoreCommand="@{viewModel.loadMoreCommand}"/>
     x
    

    具体想了解更多请查看 MVVM Light Toolkit 使用指南,里面有比较详细地讲解Command的使用。当然Command并不是必须的,你完全可以依照自己的习惯和喜好在ViewModel写Listener,不过使用Command可以使ViewModel更简洁易读。你也可以自己定义更多的、其他功能的Command,那么ViewModel的事件处理都是托管ReplyCommand来处理,这样的代码看起来会比较美观和清晰。Command只是对UI事件的一层隔离UI层的封装,在事件触发时把ViewModel层可能需要的数据传给ViewModel层,对事件的处理做了统一化,是否使用的话,还是看你个人喜好了。

    Child ViewModel(子ViewModel)

    子ViewModel的概念就是在ViewModel里面嵌套其他的ViewModel,这种场景还是很常见的。比如说你一个Activity里面有两个Fragment,ViewModel是以业务划分的,两个Fragment做的业务不一样,自然是由两个ViewModel来处理,这时候Activity对应的ViewModel里面可能包含了两个Fragment各自的ViewModel,这就是嵌套的子ViewModel。还有另外一种就是对于AdapterView,如ListView RecyclerView、ViewPager等。

      //Child ViewModelpublic final 
       ObservableList<ItemViewModel> itemViewModel = new ObservableArrayList<>();
    

    它们的每个Item其实就对应于一个ViewModel,然后在当前的ViewModel通过ObservableList持有引用(如上述代码),这也是很常见的嵌套的子ViewModel。我们其实还建议,如果一个页面业务非常复杂,不要把所有逻辑都写在一个ViewModel,可以把页面做业务划分,把不同的业务放到不同的ViewModel,然后整合到一个总的ViewModel,这样做起来可以使我们的代码业务清晰、简短意赅,也方便后人的维护。

    总的来说,ViewModel和View之前仅仅只有绑定的关系,View层需要的属性和事件处理都是在XML里面绑定好了,ViewModel层不会去操作UI,只是根据业务要求处理数据,这些数据自动映射到View层控件的属性上。关于ViewModel类中包含哪些模块和字段,这个需要开发者自己去衡量,我们建议ViewModel不要引入太多的成员变量,成员变量最好只有上面的提到的5种(context、model……),能不引入其他类型的变量就尽量不要引进来,太多的成员变量对于整个代码结构破坏很大,后面维护的人要时刻关心成员变量什么时候被初始化、什么时候被清掉、什么时候被赋值或者改变,一个细节不小心可能就出现潜在的Bug。太多不清晰定义的成员变量又没有注释的代码是很难维护的。

    另外,我们会把UI控件的属性和事件都通过XML(如bind:text=@{...})绑定。如果一个业务逻辑要弹一个Dialog,但是你又不想在ViewModel里面做弹窗的事(ViewModel不希望做UI相关的事)或者说改变ActionBar上面的图标的颜色,改变ActionBar按钮是否可点击,这些都不是写在XML里面(都是用Java代码初始化的),如何对这些控件的属性做绑定呢?我们先来看下代码:

    public class MainViewModel implements ViewModel {
    ....
    //true的时候弹出Dialog,false的时候关掉dialog
    public final ObservableBoolean isShowDialog = new ObservableBoolean();
    ....
    .....
    }
    // 在View层做一个对isShowDialog改变的监听
    public class MainActivity extends RxBasePmsActivity {
    
    private MainViewModel mainViewModel;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    ..... 
    mainViewModel.isShowDialog.addOnPropertyChangedCallback(new android.databinding.Observable.OnPropertyChangedCallback() {
          @Override
          public void onPropertyChanged(android.databinding.Observable sender, int propertyId) {
              if (mainViewModel.isShowDialog.get()) {
                   dialog.show();
              } else {
                   dialog.dismiss();
              }
           }
        });
     }
     ...
    }
    

    简单地说你可以对任意的ObservableField做监听,然后根据数据的变化做相应UI的改变,业务层ViewModel只要根据业务处理数据就行,以数据来驱动UI。

    ViewModel与Model的协作  

    从图1中,ViewModel通过传参数到Model层获取网络数据(数据库同理),然后把Model的部分数据映射到ViewModel的一些字段(ObservableField),并在ViewModel保留这个Model的引用,我们来看下这一块的大致代码(代码涉及简单的RxJava,如看不懂可以查阅入门一下):

     //Model
     private NewsDetail newsDetail;
    
     private void loadData(long id) {  
       //  Observable<Bean> 用来获取网络数据
       Observable<Notification<NewsDetailService.NewsDetail>>   newsDetailOb =   
       RetrofitProvider.getInstance()
                      .create(NewsDetailService.class)   
                      .getNewsDetail(id)                   
                      .subscribeOn(Schedulers.io())      
                      .observeOn(AndroidSchedulers.mainThread())
                     // 将网络请求绑定到Activity 的生命周期
                      .compose(((ActivityLifecycleProvider) context).bindToLifecycle()) 
                     //变成 Notification<Bean> 使我们更方便处理数据和错误
                      .materialize().share();  
    
     // 处理返回的数据
       newsDetailOb.filter(Notification::isOnNext)         
                   .map(n -> n.getValue())    
                   // 给成员变量newsDetail 赋值,之前提到的5种变量类型中的一种(model类型)        
                   .doOnNext(m -> newsDetail = m)   
                   .subscribe(m -> initViewModelField(m));
    
     // 网络请求错误处理
        NewsListHelper.dealWithResponseError(
          newsDetailOb.filter(Notification::isOnError)        
                      .map(n -> n.getThrowable()));
    }
    //Model -->ViewModel
    private void initViewModelField(NewsDetail newsDetail) {  
         viewStyle.isRefreshing.set(false);   
         imageUrl.set(newsDetail.getImage());    
         Observable.just(newsDetail.getBody())
                .map(s -> s + "<style type=\"text/css\">" + newsDetail.getCssStr())           
                .map(s -> s + "</style>")            
                .subscribe(s -> html.set(s));   
         title.set(newsDetail.getTitle());
     }
    

    注1:我们推荐MVVM和RxJava一块儿使用,虽然两者皆有观察者模式的概念,但是RxJava不使用在针对View的监听,更多是业务数据流的转换和处理。DataBinding框架其实是专用于View-ViewModel的动态绑定的,它使得我们的ViewModel只需要关注数据,而RxJava提供的强大数据流转换函数刚好可以用来处理ViewModel中的种种数据,得到很好的用武之地,同时加上Lambda表达式结合的链式编程,使ViewModel的代码非常简洁同时易读易懂。

    注2:因为本文样例Model层只涉及到网络数据的获取,并没有数据库、存储、数据状态变化等其他业务,所以本文涉及的源码并没有单独把Model层抽出来,我们是建议把Model层单独抽出来放一个类中,然后以面向接口编程方式提供外界获取和存储数据的接口。

    ViewModel与ViewModel的协作

    在图1中我们看到两个ViewModel之间用一条虚线连接着,中间写着Messenger。Messenger可以理解是一个全局消息通道,引入Messenger最主要的目的是实现ViewModel和ViewModel的通信,虽然也可以用于View和ViewModel的通信,但并不推荐。ViewModel主要是用来处理业务和数据的,每个ViewModel都有相应的业务职责,但是在业务复杂的情况下,可能存在交叉业务,这时候就需要ViewModel和ViewModel交换数据和通信,这时候一个全局的消息通道就很重要。

    关于Messenger的详细使用方法可以参照 MVVM Light Toolkit 使用指南的 Messenger 部分。这里给出一个简单的例子仅供参考:场景是这样的,你的MainActivity对应一个MainViewModel,MainActivity 里面除了自己的内容还包含一个Fragment,这个Fragment 的业务处理对应于一个FragmentViewModel,FragmentViewModel请求服务器并获取数据。刚好这个数据MainViewModel也需要用到,我们不可能在MainViewModel重新请求数据,这样不太合理,这时候就需要把数据传给MainViewModel,那应该怎么传呢,如果彼此没有引用或者回调?那么只能通过全局的消息通道Messenger。

    FragmentViewModel获取消息后通知MainViewModel并把数据传给它:

    combineRequestOb.filter(Notification::isOnNext)        
    .map(n -> n.getValue())        
    .map(p -> p.first)        
    .filter(m -> !m.getTop_stories().isEmpty())        
    .doOnNext(m ->Observable.just(NewsListHelper.isTomorrow(date)).filter(b -> b).subscribe(b -> itemViewModel.clear())) 
    // 上面的代码可以不看,就是获取网络数据 ,通过send把数据传过去
    .subscribe(m -> Messenger.getDefault().send(m, TOKEN_TOP_NEWS_FINISH));
    

    MainViewModel接收消息并处理:

     Messenger.getDefault().register(activity, NewsViewModel.TOKEN_TOP_NEWS_FINISH, TopNewsService.News.class, (news) -> {
    // to something....
    }
    

    在MainActivity onDestroy取消注册就行了(不然导致内存泄露):

     @Override
     protected void onDestroy() {    
          super.onDestroy();      
          Messenger.getDefault().unregister(this);
     }
    

    上面的例子只是简单地说明,Messenger可以用在很多场景,通知、广播都可以,不一定要传数据,在一定条件下也可以用在View层和ViewModel上的通信和广播,运用范围特别广,需要开发者结合实际的业务中去做更深层次的挖掘。

    总结和源码

    本文主要讲解了一些个人开发过程中总结的Android MVVM构建思想,更多是理论上各个模块如何分工、代码如何设计。虽然现在业界使用Android MVVM模式开发还比较少,但是随着DataBinding 1.0的发布,相信在Android MVVM 这一领域会更多的人来尝试。刚好我最近用MVVM开发了一段时间,有点心得,写出来仅供参考。

    本文和源码都没有涉及到单元测试,如果需要写单元测试,可以结合Google开源的MVP框架添加Contract类实现面向接口编程,可以帮助你更好地编写单测。同时MVP和MVVM并没孰好孰坏,适合业务、适合自己的才是最有价值的,建议结合Google开源的MVP框架和本文介绍的MVVM相关的知识去探索适合自己业务发展的框架。

    MVVM Light Toolkit只是一个工具库,主要目的是更快捷方便地构建Android MVVM应用程序,在里面添加了一些控件额外属性和做了一些事件的封装,同时引进了全局消息通道Messenger,个人觉得用起来会比较方便,你也可以尝试一下。当然这个库还有不少地方需要完善和优化(后续会持续改进),如果不能达到你的业务需求,可以clone下来自己做一些相关的扩展。如果想更深入了解MVVM Light Toolkit,请看我这篇博文 MVVM Light Toolkit 使用指南

    项目的源码地址 https://github.com/Kelin-Hong/MVVMLight 。 其中:

    library是MVVM Light Toolkit的源码,源码很简单,感兴趣的同学可以看看,没什么技术难度,可以根据自己的需求,添加更多的控件属性和事件绑定。

    sample是一个实现知乎日报首页样式的Demo,本文的代码实例均出自这个Demo,代码包含了一大部分MVVM Light Toolkit的使用场景(Data、Command、Messenger均有涉及),同时sample严格按照本文阐述的MVVM的设计思想开发,对理解本文会有比较大的帮助。

    本文和源码涉及RxJava+Retrofit+Lambda如有不懂或没接触过,花点时间入门一下,用到的都是比较简单的东西。




    发现文章有错误、对内容有疑问,都可以关注美团点评技术团队微信公众号(meituantech),在后台给我们留言。我们每周会挑选出一位热心小伙伴,送上一份精美的小礼品。快来扫码关注我们吧!

    展开全文
  • 编程理论 —— 计算图框架

    千次阅读 2018-01-14 19:18:05
    当前大部分的深度学习框架(tensorflow、theano、mxnet)都要求能否构建计算图,以及编译计算图来自动求导; 1. 命令式编程与符号式编程 命令式编程,程序中可能会存在 for或 if 形式的控制流,即循环迭代的次数...

    当前大部分的深度学习框架(tensorflow、theano、mxnet)都要求能否构建计算图,以及编译计算图来自动求导;

    1. 命令式编程与符号式编程

    • 命令式编程,程序中可能会存在 forif 形式的控制流,即循环迭代的次数和 if 分支的执行都取决于入参,不同的输入会使得程序的执行不同。对于计算图框架来说,这就对应于动态图,即图的结构(不只是结果)会随着输入的变化而发生变化;

    references

    展开全文
  • 构建面向大众的多元化全民健身服务体系框架,肖宗涛,张江林,运用文献资料法、调查法、逻辑分析法结合实证分析,探索了更具一般性的全民健身服务体系的理论表述和更具操作性的服务体系框架
  • 智能IoT系统框架理论

    千次阅读 2016-10-15 22:14:49
    SEG3.0理论已经在M3框架中实现,被FIESTA-IoT欧盟平台扩展。M3实现了利用语义web技术语义标注化传感器数据的IoT应用程序的快速原型设计。 三、网络服务层: 使得开发者能够更加容易的在虚拟化层的IoT...
    目前IoT的问题:
    1、一个IoT架构应该独立于不同的协议标准,应该提供协议的集成和不同协议的转换。
    2、大部分的IoT应用程序都局限于单个领域,使得大多数情况下部分的传感器都是重复而不需要的。怎样让传感器设备应用程序到多个领域,实现设备的可重用性。
    3、IoT系统应该提供给人们更高层次的实体信息,而不是传感器本身的原始数据。
    4、像大多数底层的协议,设备没有用通俗的术语来描述IoT数据,传统的服务模型只提供了未加工的数据,这些数据不包含任何聚合的描述,在实际应用程序中需要将这些数据包装以及专业化。

    智能IoT系统分为三层:
    一、物理层
          负责将物理设备转换成应用程序可以交互的设备。其中网关使用具体设备的协议去检索底层提供的数据,并且对数据添加语义,进而利用语义web(例如:RDF,OWL)去整合数据。大多数情况下,设备是需要通过API直接和应用程序联系,但是这就要求设备能够支持HTTP或者TCP/IP协议,而这些协议对于设备来说是很复杂的,所以需要提供一个网关节点来实现设备与应用程序的互通。

    这种网关就为资源约束的设备和IoT应用程序提供了一个桥梁,应用程序就可以通过多个网关节点来收集数据。上图系统被称为Semantic Gateway as Service(SGS)系统,能够充当设备与IoT应用程序服务的桥梁。主要有三个功能:
    1、它可以连接基于不同协议的设备到网关组件,比如MQTT,XMPP或者CoAP协议。
    2、网关能够为外部的云服务或者其他基于REST或者Pub/Sub 协议的SGS系统提供接口。
    3、能够捕获来自W3C SSN信宿节点的数据,以及在转发数据到网关接口服务之前特定区域化本体。
          这样做的好处在于可以利用标准机制和词汇将传感器数据语义标注,以便提供IoT系统垂直竖井之间的互操作性。通过整合这些标签数据,并提供具有语义web的消息传递接口。这样第三方服务就可以将传感器的观测值抽象为更高级的数据。网关设备分离了物理层的设备和IoT应用程序服务。它提供了一个IoT应用程序服务使用rest和pub/sub的接口端点。

    二、虚拟化层
          负责管理框架数据和推导出新的知识,可用化底层提供的数据,通过使用推导引擎和在线的web知识推导出高级数据,利用这些丰富的数据帮助网络层去建立智能系统,应用程序和服务。
          大多数时候,未处理的数据仅仅是个数字,人们只知道这个数据来自哪个单元,哪个传感器。智能IoT系统就需要将多个传感器的数据整合,理解数据的含义,以便提供决策或建议。处理异构数据的互操作性,就需要建立更聪明的IoT系统。数据被存储在不同的文件(例如:CSV,Excel),以及不同的存储格式(例如:ontology,schemas)。在处理异构数据时,使用语义web技术能够带来好处:1、统一数据,2、连接IoT数据到外部的知识库,3、显示的添加原始数据,4、推导出新的知识。语义web技术使得知识谱之间能够相互连接。让IoT数据与这些知识谱相连能够使IoT系统更加智能化。一个目前广泛使用的知识谱是Linked Open Data(LOD)。像Facebook和Google都在基于schema.org构建自己的知识谱,被广泛应用到搜索引擎,另外有LOD组件,例如维基百科,DBpedia等。这样的知识谱使得获取信息能够更加方便和自动化,是原始数据抽象为更高级数据的基础。将统一的,语义丰富的IoT数据和通过网络连接这些知识库来建立智能系统具有巨大的潜能。比如,将健康测量值连接到医疗知识库,能够自动解释原始数据。
           目前开放的本体和数据集不相互连接,新的系统需要将两者连接起来,同时在结构化的数据中推导出新的知识。结合来自异构数据源的数据和构建创新可互操作的应用程序程序需要不同的过程和步骤。图4介绍了SEG3.0方法论旨在满足这些需求包括以下步骤:(1)组成(2)建模(3)连接(4)推理(5)查询(6)服务(7)服务合成。SEG3.0鼓励增强数据到应用程序的语义互操作性,这种灵感来自于基于图4描述的“共享与重用”的方法。SEG3.0包含:
    Linked Open Data(LOD):它是共享和重用数据的一种途径,LOD不提供任何可视化或浏览IoT数据的工具,因此,我们预想设计Linked Open Data  Cloud(LODC) for IoT,为了共享,浏览和重用传感器提供的数据。
    Linked Open Vocabularies (LOV):是一种共享和重用模型、词汇、本体的方法。它包含了LODC里面被数据集使用过的RDFS词汇的描述或者定义过的OWL本体。为了保证高质量,可重用性的本体,LOV不引用任何不符合最佳实践的本体。这意味着由于IoT社区还不知道最佳的实践,几乎所有的IoT本体和相关领域的本体不会被LOV引用。为了突破这个限制,我们提出了LOV for IoT,大约有300个基于本体的IoT项目引用的数据集,分类如下:(1)IoT应用程序领域(2)使用过的传感器(3)本体状态(比如:网络共享,是否是最佳实践过的)(4)用来推导高级知识的推导过程(5)相关项目的研究文章。这个数据集包含了一个需要的知识背景,去增加设备提供的数据的价值。
    Linked Open Reasoning(LOR)是一种共享和重用解释数据推导出新信息的方法(例如:使用过的机器学习理论,已经被专家设计过的重用规则等)的路径。 Sensorbased Linked Open Rules (SLOR)是一个用来解释原始数据的可互操作规则的数据集。
     Linked Open Services (LOS):是一种提供共享和可重用的服务或者应用程序程序的方法。构建复杂的应用程序需要多个服务合成。服务可以根据REST原则或者语义web技术的帮助来提高互操作性,这种方法也可以扩展为一套可互操作的服务设计。
           仅仅共享和重用数据是不够的,从LOD到LOS整个链都应该被共享和重用,以此来提高互操作性以及从数据中获取有意义的知识。SEG3.0理论已经在M3框架中实现,被FIESTA-IoT欧盟平台扩展。M3实现了利用语义web技术语义标注化传感器数据的IoT应用程序的快速原型设计。

    三、网络服务层:
    使得开发者能够更加容易的在虚拟化层的IoT数据上建立大规模的,更有意义的IoT应用程序和服务。该层主要目的是为了彻底的减少IoT应用程序开发,从而使能快速原型设计和激励众多服务的互通性。该层离终端使用更近,能够在智能设备上创建智能应用程序。下面描述了应用程序程序开发的方法来构建IoT应用程序:
    1、通用编程:目前,IoT的开发是处于节点级的,开发人员直接关心每个设备的操作。比如开发者使用通用编程语言(java,c等),专注一个特定的中间件API或者节点级的服务去实现数据通信。这种方式的优点是有效系统的开发建立在单个设备的完整控制上。由于系统的异构性使得对于IoT应用程序来说很笨重。
    2、宏编程:比如NodeRED,但是程序缺乏重用性和设计平台。
    3、基础云平台:为了改善开发的努力,基础云平台提供APIs ,提供实现IoT应用程序的共同功能(例如:为了数据可视化,需要发送和存储数据到云端)。而且平台还提供通过文本和可视化编程写一个自定义的应用程序程序逻辑。他们提供高级协作行为的抽象,同时隐藏底层细节,例如消息传递。一个基础云平台的例子就是IBM-IoT基础平台。这是一个充分的管理和云托管服务,使得从物理设备获取价值变得简单。利用抽象,开发人员可以将设备连接到互联网,将传感数据通过MQTT协议安全的传送到云平台。开发人员则可以开发各种基于云平台的服务,例如:可视化和洞悉数据的仪表板服务,存储历史数据的存储服务。
           相对于通用编程语言,相对来说云平台是一个可行的方法。它通过提供基于云平台的API来实现共同的功能,减少了开发力度。第二个优点是,因为应用程序程序逻辑位于中心位置,这种方法易于部署和演化。但是这种方法牺牲了点对点的直接通信。这点限制了开发人员实现某些功能。例如:点对点的局部通信。第三点,应用程序程序逻辑很大程度运行在一个中心云上,因此,应用程序程序依赖于云提供商的可用性。因此,它可能不适合一些关键的应用程序。
    4、模型驱动开发:提出MDD是为了解决应用程序程序对平台的依赖性。应用程序在垂直和水平上分离关注点。垂直分离原则通过从PSM模型(例如编程语言)中分离出规范平台无关模型(PIM)来减小应用程序程序开发的复杂度,水平分离原则是利用不同的系统视图来描述一个系统,每个视图描述系统的某一个方面来减少开发的复杂度。
          一个MDD的例子就是IoTSuite,它旨在让开发者开发IoT应用程序变得容易。它提供了一组指定IoT应用程序的高级语言。它提供了自动化技术去解析这些高级语言编写的规范,生成特定平台的代码。IoTSuite 集成了三种高级语言:(1)域语言来描述一个IoT应用程序程序的领域特征。(2)结构语言来描述一个IoT应用程序程序的特定功能。(3)部署语言来描述部署特定功能的有关设备的物理环境信息。IoTSuite被自动化技术支撑,如代码生成器,通过解析规范使用支持高级编程语言生成特定于平台的代码支持(即关注垂直分离)。

    注:该文章来源IEEE Xplore,初次翻译,有错误请指正。

    展开全文
  • 建立并完善财务会计概念框架,是会计理论和会计实务双重发展的客观需要。目前,我国基本会计准则还存在诸多局限性。面对新的会计环境,构建我国财务会计概念框架。应遵循系统性、中立性、前瞻性及兼顾国际化和国家化...
  • 论企业核心能力的概念、框架构建与提升,王智宁,吴应宇,无论是理论界还是实务界,核心能力绝对是当今管理领域最引人关注的问题之一,然而时至今日,人们对核心能力的概念还未形成统一的
  • 去呈现的框架的仓库,用于。 ` 进行设定 我们建议创建一个虚拟环境以使用运行VisionEngine。 安装anaconda / miniconda后,下载VisionEngine并进入HOME目录: $ git clone ...
  • 6) Web层引用其他所有层(理论上只需要引用IService、DTO和Form,全部引用只是为了方便引入各个项目中的DLL)。 7) 对于其他工具的引用(如log4net、spring.net等用的时候再说)。 5 关于项目运行的一些...
  • 入门教材,适合广泛应用,对于初学者可以进行体系建立,了解当前时代更新知识。紧跟时代变化知识体系。快来看一看。。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 87,962
精华内容 35,184
关键字:

如何构建理论框架