Android 获取使用的分寸

MVC中M层实现的规则

说了那么多,可以总计出所谓的MVVM其实并不是一种所谓的框架或者格局,他只是一个伪框架而已,他只是将功用和拍卖按文件夹的章程举办了划分,最后的的结果是系统乱成了一锅粥。毫无层次可言,所享有的绝无仅有亮点是把C层的代码和功能完全弱化了。其实出现这种规划艺术最根本的缘故就是没有对M层举办正确的知道定义和拆分。那么我们相应什么正确的来定义和计划性M层呢?下边是自我个人认为的多少个准则(也许跟其旁人的理念有出入):

  • 概念的M层中的代码应该和V层和C层完全无关的,也就是M层的对象是不需要倚重任何C层和V层的靶子而单独存在的。整个框架的统筹最优布局是V层不依赖C层而单身存在,M层不看重C层和V层独立存在,C层负责关联二者,V层只担负映现,M层持有数量和作业的具体贯彻,而C层则处理事件响应以及业务的调用以及通报界面更新。三者之间必然要强烈的定义为单向依靠,而不应当出现双向看重。下面是三层的依靠关系图:

三层之间的单向依靠关系

唯有当你系统规划的不比部分都是单向依靠时,才可能便宜的展开层次拆分以及各个层的效应独立替换。

  • M层要到位对作业逻辑实现的包装,一般工作逻辑最多的是事关到客户端和服务器之间的事情交互。M层里面要完成对利用的网络协议(HTTP,
    TCP,其他)、和服务器之间交互的数据格式(XML,
    JSON,其他)、本地缓存和数据库存储(COREDATA,
    SQLITE,其他)等所有工作细节的包装,而且那多少个事物都不可以透露给C层。所有供C层调用的都是M层里面一个个工作类所提供的成员方法来促成。也就是说C层是不需要精晓也不应有通晓和客户端和服务器通信所利用的别样研究,以及数据报文格式,以及存储方面的情节。这样的好处是客户端和服务器之间的通信协议,数据格式,以及地面存储的改动都不会影响其他的运用全体框架,因为提供给C层的接口不变,只需要提高和改进M层的代码就足以了。比如说咱们想将网络请求库从ASI换成AFN就假若在M层变化就可以了,整个C层和V层的代码不变。下边是M层内部层次的定义图:

M层内部的包裹层次

  • 既是我们的利用是一个完完全全但又分模块,那么业务层内部也应有按效能模块举行社团划分,而不应有简单且平面的依照和服务器之间通信的接口来开展工作层次的平面封装。我深信有这个人都是对M层的卷入就是简单的遵照和服务器之间的互相接口来简单的包装。下面的两种不同的M层实现的事体封装情势:

二种不同的M层封装实现

大家还足以更加的对业务逻辑抽象出M层的接口和促成两片段,这样的一个益处是相同的接口可以有两样的兑现模式,以及M层可以隐蔽万分多的内部数据和艺术而不表露给调用者知道。通过接口和实现分离我们仍可以够在不更改原先实现的底子上,重新重构业务部分的实现,同时这种格局也很容易MOCK一个测试实现,那样在举行调节时得以很粗略的在实事求是实现和MOCK实现之间切换,而不用每便都和劳动器端举办交互调试,从而实现客户端和服务器之间的分级支付和调试。上面是一个升格版本的M层连串布局:

基于接口的M层实现

  • M层怎么着和C层交互的题材也需要考虑,因为M层是不需要了解C层和V层的存在的,那么M层在事情处理完毕后怎么着去通告C层呢?方法有很多种:
    • 咱俩得以为M层的通报逻辑定义Delegate协议,然后让C层去落实这个协议,然后M层提供一个delegate属性来赋值处理事务通告的对象。
    • 大家也可以定义众多的NSNotification或者事件总线,然后当M层的事情处理完毕后方可发送通告,并且在C层实现布告的处理逻辑。
    • 我们得以用闭包回调或者接口匿名实现目标的花样来贯彻工作逻辑完成的通报功能。而且可以定义出标准:所有M层对象的措施的最后一个参数都是一个正规的如下格式的block或者接口回调:

typedef void (^UICallback)(id obj, NSError * error);

这种格局其实在重重系统中有应用到。我们可以参数考苹果的CoreLocation.framework中的地理地点反解析的类CLGeocoder的定义。还有一些的是在AFN以及ASI中的网络请求部分都是把成功和失利的拍卖分成了2个block回调,不过这里提议在给C层的异步通告回调里面不区分2个block来调用,而是一个block用2个参数来解决。因为有可能大家的拍卖中不管成功依然败诉都可能有一部分代码是一般的,如果分别则会产出重复代码的题材。

进而就意识一个问题,2.3的版本的确可以用。然而4.2以及上述版本就报错了。经过查证发现
PackageManager.getPackageSizeInfo(String packageName,
IPackageStatsObserver
observer)不可用,改为PackageManager.getPackageSizeInfo(String
packageName, int userHandle, IPackageStatsObserver observer)。

梦想后续

MVVM被引入的前因后果

粗粗是在二零一零年左右平移端支付火了起来,起始是iOS,Android,
WinPhone五个大平台竞争,后来后者退出了角逐,变成了二分天下。从利用系统布局以及为开发者提供的框架类别来看,五个平台都是生产了经典MVC三层结构的开发情势,这三层所代表的意思是模型、视图、控制。这一个开发框架的初衷其实也很简单:视图负责显示和渲染,模型负责作业逻辑的贯彻,控制负责调度视图的事件以及业务逻辑的调用以及通知视图的基础代谢公告。
三有的松散耦合,各司其职。下面是经典的MVC框架结构:

[图形上传失利…(image-1d68cb-1512992093070)]

一个很心痛的真相是随便是Android和iOS都只对C和V两片段开展了正规的概念和实现:Android的视图部分的实现是概念了各样控件以及通过XML文件来组装视图布局界面,iOS的视图的贯彻也是概念了各类控件以及由此XIB或SB来组装视图布局界面;
Android的支配部分则是通过Activity来兑现,而iOS的决定部分则是经过UIViewController来实现的。而模型部分吗?因为各样应用的作业逻辑和采取场景并不相同,所以两个阳台也无力回天也不可能定义出一个通用的模型层出来,而是把模型层的定义留给了开发者来兑现。不过这为大家的开发者在采取MVC框架开发使用时埋下了隐患。

早期的行使开发相对简便易行,因为没有标准的模型层的定义,而控制层又在工程变更时预留了无数可供开发者写代码的地点,所以众多开发人士就自但是然的将事情逻辑、网络请求、数据库操作、报文拼装和剖析等等全部代码都放入了控制层里面去了,根本就不需要哪些模型层的定义。
这样随着时光的延迟和应用的纷繁增添,就应运而生了C层膨胀的情形了。一个控制器的代码可能出现了好几千行的面貌。于是乎有人就从头找解决方案来为C层瘦身了。又一个很惋惜的真情是还并未人去想着抽象出M层,而是用了之类方法来解决问题:

  • 客户端和服务器之间交互的数码报文是否足以定义出一个个只有属性而尚未办法的多少对象啊?这样在处理和渲染界面时就不需要和原来的XML或者JSON或者其他的格式报文交互了,只要操作数据对象就好了。于是解决方案就是基于客户端和服务器之间交互报文定义出一个个的数据模型,然后再付出出一套XML或者JSON和数据模型之间互转的解析器来。最终将这个个只有多少而从不章程的靶子数据模型统一置于一个地点,然后给他们定义为M模型层(呼!终于给出模型层的定义了,可是:Are
    you kidding
    me??)
    。这样C层就不会再出现XML或JSON解析以及向来读取报文的代码了!而是把这有的代码挪到模型层了(我们来看呀,我好不容易应用上了MVC框架了!)
    好了!瘦身第一步成功。不过只是,问题还在啊,我的作业逻辑依然一大片在C层啊,看来MVC这种框架也然则这样啊!根本没有解决本身的题目。不行,我无法再用MVC这种框架来开发自己的运用了,我要另找它法,要继续对C层瘦身。

  • 我的某个界面和某个业务逻辑是绑定在一块的,这多少个界面的突显是通过调用某个业务逻辑来促成的,业务逻辑完成后要直接更新这一个界面。这种环环相扣的调用和换代关系平素就不需要C层的参预。因而得以将这有些界面的立异刷新和事情逻辑的调用绑定在一块儿,
    二者结合为一个查封而独自的完好并形成独立的类。这样把这些类的代码抽离出来了,存放到一个独门的公文夹中。我把这么些部分叫什么好呢?对了就叫视图模型层VM吧!视图模型层中的类定义了一个给外部使用的绝无仅有接口来供C层调用。这样自己好不容易把一大一些代码从C层中抽离出来了。我曾经打响的落实了C层的更是瘦身,并抽象出了一个视图模型层了!(不过哪儿好像不对,视图模型层设计到了视图、模型、视图模型层三地点的相互和耦合)
    不过没有提到,反正自己的C层进一步瘦身成功了!,我看看还可不得以继承瘦身C层?

V和VM以及M之间的依赖关系

  • 自身的过多视图的轩然大波是在C层中处理的,这自己是不是可以把C层的事件处理也拿出去呢?
    干脆就拿出去吧。然则怎么拿出去啊?于是乎我又不停的搜索,终于找到一个叫RAC的东西了,这多少个东西好啊,他可以承受处理视图的各类风波,以及可以承担连续的网络调用。等等。。。
    RAC就是有点晦涩难懂!难以学习,代码难以阅读和调试。如何做?
    没有关联,只尽管能将C层的代码瘦身这多少个又算怎么。。。大不断就是多趟一点坑,多搞几回培训就好了。
    嗯! 就这么办,那我把这部分代码也放入到VM层里面去呢。

    。。。。呼!!!
    C层终于瘦身成功。然后我们看呀,我的C层里面确实是什么样代码也尚未了。。。
    它不再处理视图的风波了,因为事件让RAC给处理了、它也不处理视图的基础代谢和业务逻辑的调用了因为让视图模型MV给处理掉了、他也不处理数量的解析了因为让模型层给替换掉了。嗯。。。。我要给那种没有C层或者不需要C层的框架起个名字,叫什么好啊?
    就叫:MVVM吧。。。
    我的使用能够毫不C层了,然后我就奔走相告。将C层无用大白于天下。。

真的是这么呢?答案是NO!!!

首先自己想说的是一个美好的框架中各层次的拆分并不是简单的将代码举行分类和剪切,**层次的分割是横向的,而模块的细分则是纵向的
** 。
那中间涉嫌到了层次之间的耦合性和任务的分割,以及层与层之间的互相接口定义和措施,同时层内的筹划也应该享有惊人的内聚性和结构性。而这个规划的要求并没有在所谓的MVVM中反映出来。

  • 第一要正确的理解MVC中的M是什么?他是数据模型吗?答案是NO。他的没错定义是业务模型。也就是您所有业务数据和事务实现逻辑都应该定义在M层里面,而且工作逻辑的落实和概念应该和切实的界面无关,也就是和视图以及控制之间没有此外的关联,它是足以独自存在的,您还能够将业务模型单独编译出一个静态库来提供给第三方或者其他系统使用。在上头经典MVC图中也很清楚的叙说了这或多或少:**
    控制负责调用模型,而模型则将处理结果发送通告给控制,控制再文告视图刷新。由此我们不可能将M简单的知晓为一个个单调的只有属性而从不办法的数据模型。其实这其中涉及到一个最核心的计划性条件,这就是面向对象的主干计划原则:就是如何是类?类应该是一个个兼有相同操作和不同性质的目标的架空。
    我想前些天其他一个系列里面都未曾出现过一堆唯有多少而从未艺术的数据模型的聚集被定义为一个独门而空虚的模子层来供我们使用啊。**
    我们无法把一个保留数据模型的文书夹来作为一个层,这并不符合横向切分的平整。所以说MVVM里面的所谓对M层的定义就是一个伪概念。

  • 下面我早就认证M层是业务模型层而非数据模型层,业务模型层应该封装所有的事务逻辑的兑现,并且和求实视图无关。大家无法将一个视图的显现逻辑绑死在一个政工处理逻辑之中,因为有可能存在一个工作逻辑有多种不同的变现格局,也恐怕界面显示会随着应用升级而变更,不过事情逻辑是对峙平静的。尽管是某个视图确实就跟这多少个业务是一环扣一环耦合的,也不应有做强耦合绑定。所以地点所谓的VM这种将视图的来得和工作的处理逻辑绑定在一块是老大不佳的法门,因为如此的筹划方法已经完全背离了系统内部最核心的来得和落实应有分别处理原则。而且这种计划的思考是和分支的看法是违反的。因为他出现了视图和业务的紧耦合和交互双向倚重问题,以及和所谓的M层也要紧耦合的留存。所以说MVVM里面所谓的VM层的概念也是一个伪概念。所谓的VM层这之中只不过是按页面举行的效率拆分而已,根本就谈不上所谓的层的定义。

  • 再来说说事件处理。经典的C层设计的目标是负责事件处理和调度,不论是按钮点击如故UITableview的delegate以及ListView的Adapter都最好放在C层来处理,这也是符合C层最实质的定义:就是C层是一个担当调度和控制的模块,它是V层和M层的粘合剂,他的效能就是处理视图的事件,然后调用业务逻辑,然后接受工作逻辑的处理结果通告,然后再通报视图去刷新界面,这就是C层存在的意义。而且系统默认也是按这一个点子设计的。而RAC的面世则将这部分的拍卖给活生生的替代掉了。也就是经过RAC所谓的响应式和触发式这种体制就能落实将事件的调度处理放在其他地点其他时候都能一气浑成。这样做的目标使得我们得以疏散和分解代码。但结果出现的问题吧?就是同一个单元调度处理逻辑和效能的构建完全放在了一个地点,但不同的单元逻辑的又分散在不同的地点,不可能去分类统一保管和保养。由此你不可能一下子就知晓某个意义有所调度到底是咋样促成以及在何地实现的。因为RAC将功用构建和事件处理完全粘合到一个大的函数体内部,并且是代码套代码的形式,这种方法严重的毁损了面向对象里面的构建和拍卖分离的设计格局理论。更麻烦的是其高昂的求学和保障资金,代码阅读精通困难,以及无处不在的闭包使用。试想一下那一个对于一个初大方的话是不是噩梦?,一旦出了问题对于维护和代码调试是不是噩梦?而且使用不当就会并发循环引用的要紧问题。那样一来原本C层一个调度总管的天职被RAC来接管后,这多少个处理将变得分散和无序,当大家要做一些集合的保管比如HOOK和AOP方面的东西时就变得不能出手了。
    不可否认的是RAC在处理连续调用以及各样响应方面有自然的优势。一个例子是我们可能有连日的六个跟服务器的网络请求,那时候用RAC举办这种拍卖能便于的化解问题。可是本人想说的是当存在这种景色时,大家越来越应该将这种连接的网络调用在M层内部消化掉,而只给C层提供一个简短而方便的接口,让C层根本不需要关爱这种调用的连续性。因而可以说为了把C层的代码给消化掉而引入RAC的建制,不仅没有简化掉系统反而下跌了系统的可维护性和可读性。RAC机制根本就不切合用在事件处理中。出色的使用和框架并不在代码的多寡,而是完全系统的代码简单易读,各部分任务分明,容易保障的调节

—— MVVM被引入的根本原因是对M层的错误认识所引起的 ——

之所以我们代码需要做如下的改动:

MVC中M层实现的简约举例

最终大家以一个简便的用户体系的报到序列来实现一个M层。

1.概念标准的M层异步回调接口:

//定义标准的C层回调block。这里面的obj会根据不同对象的方法的返回而有差异。
typedef void (^UICallback)(id obj, NSError * error);

//这里定义标准的数据解析block,这个block供M层内部解析用,不对外暴露
typedef id (^DataParse)(id retData, NSError * error);

2.定义所有M层业务类的基类,这样在通用基类里面大家可以做过多处理。比如网络层的联结调用,加解密,压缩解压缩,我们仍可以做AOP和HOOK方面的拍卖。

     @interface  ModelBase

           //定义一个停止请求的方法
           -(void) stopRequest;
           /**
             *定义一个网络请求的唯一入口方法
             * url 请求的URL
             * inParam: 入参
             * outParse: 返回数据解析block,由派生类实现
             * callback: C层通知block
             */
           -(void) startRequest:(NSString*)url  inParam:(id)inParam outParse:(DataParse)outParse  callback:(UICallback)callback;
     @end

3.定义一个用户类:

    @interface  ModelUser:ModelBase

        @property(readonly) BOOL isLogin;
        @property(readonly) NSString *name;

       //定义登录方法,注意这个登录方法的实现内部可能会连续做N个网络请求,但是我们要求都在login方法内部处理,而不暴露给C层。
       -(void)login:(NSString*)name  password:(NSString*)password   callback:(UICallback)callback;
        //定义退出登录方法
       -(void)logout:(UICallback)callback;
    @end

4.定义一个M层总体系统类(可选),这么些类可以是单例对象:

    @interface ModelSystem:ModelBase

     +(ModelSystem*)sharedInstance;

    //聚合用户对象,注意这里是readonly的,也就是C层是不能直接修改用户对象,这样保证了安全,也表明了C层对用户对象的使用权限。
    @property(readonly)  ModelUser *user;  

    //定义其他聚合的模块

    @end

5.在C层调用用户登录:

  @implementation LoginViewController

    -(IBAction)handleLogin:(UIButton*)sender
   {
        sender.userInteractionEnabled = NO;
        __weak LoginViewController  *weakSelf = self;
       [[ModelSystem sharedInstance].user  login:@"aaa" password:@"bbb"  callback:^(ModelUser *user, NSError *error){

        if (weakSelf == nil)
               return;
       sender.userInteractionEnabled = YES;
       if (error == nil)
       {
              //登录成功,页面跳转
       }
       else
      {
            //显示error的错误信息。。
      }}];

   }

   @end

可以观看地点的C层的一对异常简单明了,代码也易读和容易精通。同时我们还观看了C层跟本不需要通晓M层的记名实现到底是怎么请求网络的,以及呼吁了多少个网络操作,以及用的咋样协议,以及咋样数据报文格式,所有的这整个都封装在了M层内部贯彻了。C层所要做的就是简单的调用M层所提供的法门,然后在callback中通报界面更新即可。整个C层的逻辑也就是几十行就能搞定了。

切切实实的模型层设计方法请参见M层的规划


迎接我们关注本身的github地址,关注欧阳四弟2013,关注我的简书地址:http://www.jianshu.com/u/3c9287519f58

本条会作为自身监听apk中的一个模块存在~~~

一贯都有人撰文吹捧MVVM应用开发框架,著作把MVVM说的好听并且批评包括iOS和android所用的MVC经典框架。这篇著作就是想给这个捧臭脚的人们泼泼冷水,尽管有可能导致骂声一片,但是目标是给那多少个刚入门的伴儿一些参考和提议,以免误入歧途。同时也给这个深陷其中无法自拔的同伙们敲敲警钟,以免其在错误的征程上越走越远。

以及

目录

基本代码:

—— MVVM并非框架,而只是简短的公文夹分类 ——

在此间我们用到了之类的:

个中一个就是亟需去拿到Android应用的轻重缓急,我们现在本人的apk依旧会做的尽心小,不过用了一段时间之后apk的占用量就会愈加大,自然那多少个也是性质测试需要监控的多少之一。

日前在搭建兼容性性能平台,如今架构图仍旧中间才可以见到,具体之后做完我会开放出来。

下一场我install到了Nexus5
Android5.0下边,点击一个施用之后看到如下Log,表达成功了~~~