Prism vs MvvmCross
Prism vs MvvmCross
在上一篇Xamarin开发环境及开发框架初探中,曾简单提到MvvmCross这个Xamarin下的开发框架。最近又评估了一些别的,发现老牌Mvvm框架Prism现在也支持Xamarin Forms了,可喜可贺!今天我们就来近距离尝试、比较一下,分别基于这两个框架写一个简单Android/iOS跨平台应用的感受。
Prism
Prism框架应该来源于微软的Microsoft patterns & practices的Prism Guidance。最初,应该被更多用于WPF开发。我对WPF了解太少,就不评论它的过去了,我们这里重点关注他目前Preview状态的Prism Xamarin Forms支持。它提供了一个VS2015的模版插件,可以从这里直接下载安装,也可以从VS2015的Extensions and Updates菜单里面下载安装。安装这个插件,并重启VS2015后,我们可以看到,项目模版里多了一个Prism分组,包含三个项目类型,其中一个是Prism Unity App (Forms),就是for Xamarin Forms的。名字里包含Unity,那是指这个模版使用Unity DI框架。
事实上Prism支持Autofac,NInject等各种DI框架,不过模版只有Unity的。我们来尝试新建一个项目。相比于Xamarin官方及其他开发框架,它的项目模版,提供了非常友好的UI,可以选择新建的项目需要支持哪些平台。如下图:
我们就选Android和iOS。新建的项目很自然的包含一个PCL格式的共享项目,和一个Droid项目,一个iOS项目:
从目录结构来看,和Xamarin Forms官方的模版生成的项目非常类似,表面看来,好像就是在共享项目里多了ViewModels和Views目录。我们来看看Droid的MainActivity类,我们知道这个类是每一个Xamarin Droid项目的入口类,基本相当于Console程序的Main方法的地位。可以看到,LoadApplication()方法还是接受一个App类的instance,(这个类还是定义在共享项目里的,我们下面再细说),不过,这个App类的构造函数接受一个实现了Prism的IPlatformInitializer接口的AndroidInitializer。它只包含一个RegisterTypes(UUnityContainer container)方法,非常容易理解,就是用来配置Unity容器的,我们可以在这里注册各种业务层、数据层等等的接口和类到Unity。
好像Droid项目相比官方Xamarin Forms模版也就这点区别了,可见Prism对官方模版架构的改动非常小。我们再来看看iOS项目的AppDelegate类。这个类和MainActivity的地位相当,也是iOS项目的入口类。看上去也是和MainActivity做的事情非常类似,这里也包含一个iOSInitializer类实现了IPlatformInitializer接口。太容易理解了,自描述,都不需要文档,我喜欢。
下面就剩下在共享项目了。我们先来看看App类,它还是包含一个App.xaml和一个code behind文件。App.xaml看上去和Xamarin Forms官方模版的不一样了,它继承于PrismApplication类。
App.xaml.cs的内容就有比较大的不同了。首先,他当然需要接受一个IPlatformInitializer,并传递给基类,这个容易理解。此外,两个override方法,一个RegisterTypes()用于注册功能页面。另一个OnInitialized()用于指定默认打开那个页面,并且还可以给页面传参数。还是足够简单的。
很明显,项目运行时,会先显示MainPage,而MainPage的xaml和对应的ViewModel分别定义在Views目录和ViewModels目录中。MainPage是一个标准的xaml page,唯一的和Xamarin Forms版本不同的是,它包含了一个prism:ViewModelLocator.AutowireViewModel="True"的属性,从字面意思,我们就能知道,它表示,他会自动resolve并绑定到一个同名ViewModel,也就是ViewModels目录中的MainPageViewModel类。而这个类的实现也是不能再简单了。主要就一个构造函数加两个方法,一个OnNavigatedFrom(),一个OnNavigatedTo(),真的不需要文档,就能理解,一个是页面load时执行的逻辑,一个是页面离开时执行的逻辑。
让我们来尝试增加一个第二个页面和对应的ViewModel,看看页面跳转怎么玩。我们来新建一个SecondPage.xaml和对应的SecondPageViewModel类。页面功能就照抄MainPage了,只是显示的text不同。然后,我们需要在App类的RegisterTypes()里注册SecondPage:
接下来,我们来给MainPage.xaml增加一个按钮,点击切换到SecondPage:
当然,MainPageViewModel里我们也要添加相应的代码,主要是,要依赖注入一个INavigationService,用来执行跳转,当然还要一个LoadSecondCommand绑定到前面那个按钮。
Ok, 运行程序,点击按钮,就能从MainPage跳转到SecondPage了。
Prism的简单示例就到这儿。总体的感觉就是,Prism框架和Xamarin Forms本身的架构结合地的非常自然,接口定义,和编码方式也非常符合一般人的思路,几乎不需文档就能理解。
MvvmCross
下面我们再来近距离看看MvvmCross的情况。MvvmCross也有一个VS2015的插件,提供了支持Forms的项目模版。我们来练一把。下载安装这个插件后。我们来新建一个项目。新建的项目是下面这个样子:
两个Test项目我们先不管。我们可以看到,它相比Prism多了不少东西,我们一个一个来看。这次,我们先从共享项目开始。Model和Repository目录可以先忽略,他们只是生成了数据访问的repository接口和Model,其实和MvvmCross本身没什么关系。Resources和Services目录也可以先放一边,因为,它们实现了一个简易的多语言支持方案,接口其实非常简单明了。ViewModels和Views目录,其实和Prism的是一个概念,不过略有差别。
第一个差别是,MainPage.xaml中定义了一个xmlns:res="clr-namespace:MvvmCrossForms1.Core.Resources;assembly=MvvmCrossForms1.Core"属性,做什么用的呢?通过它可以访问Resources目录中定义的多语言翻译的文本资源。有了它,我们可以很方便的绑定多语言文本资源到xaml上的属性。
第二个差别是,所有的ViewModel类需要继承自MvvmCross提供的MvxViewModel类。并且,需要为每个ViewModel属性的set实现,调用基类的RaisePropertyChanged()方法。这样,理论上,它就能动态获知View上的属性变更,为实现动态数据绑定,提供了可能。
接下来,是App类。虽然名字还是叫App,实际上,它这个App类并不是最终继承自Xamarin Forms的Application类的,它不是一个View,也没有xaml,而是继承于MvvmCross自己的Application类。在具体的Driod和iOS项目到时可以看到,它的框架内部实际上封装了真正的Xamarin Application类。这个App类只包含一个Initialize()方法实现,前半部分调用它的内部IoC容器的配置方法,将所有的Services和Repositories接口和类,注册到了IoC容器。中间设置了App的当前语言。最后一行,调用RegisterAppStart<ViewModels.MainViewModel>()显示默认的MainPage页面。但是注意,比较特别的是,它不是通过页面的名称,而是通过ViewModel类,强类型方式制定要显示哪个页面的。
好了,共享项目就这些特别了。我们来演示如何进行页面跳转。新建名叫SecondPage的xaml和一个名叫SecondViewModel的ViewModel类。然后,给MainPage.xaml添加一个Button如下:
然后,在MainViewModel类中,添加一个ShowSecondCommand就行了,这个比Prism的版本简单多了。注意,它这里也是通过强类型的ViewModel进行页面跳转的。强类型的好处是,如果有任何重构,所有的引用会自动更新,不像Prism的字符串,还要自己手动改。
再来看Droid项目。Droid项目的Bootstrap目录一般用于MvvmCross的各种插件的初始化,这里不详述。Services目录呢,一般用于放置共享项目中定义的某些功能接口的Droid特定实现,这里也可以先忽略。Linker类可以忽略,是它生成了给MvvmCross框架自己用的。
这个Droid项目真正的入口是SplashScreen,它基于标准的Xamarin Activity提供了一个App开机页面的默认实现。它的isInitializationComplete()方法,指定了,App完成后,显示MvxFormsApplicationActivity这个Activity。
SplashScreen的基类内部,会通过反射,去寻找项目中一个名叫Setup的类,这个Setup类里,就是放所有App初始化代码的地方。所有的初始化执行完之后,SplashScreen类的isInitializationComplete()方法才会被调用。
一旦isInitializationComplete()方法被调用,MvxFormsApplicationActivity类被执行,在它的OnCreate()方法会最终启动,定义在共享项目里的App类,然后MainPage才会被真正显示。
iOS项目的情况,略有不同,没看到类似Droid项目的SplashPage功能(可能是不同的team负责iOS和Droid部分开发的?貌似Droid版本功能更完善一些。这个还要在摸索下)。iOS项目的启动类还是AppDelegate,它的FinishedLaunching()方法简单的调用了Setup类,并且直接启动了共享代码里的App类,这样MainPage就能被显示了。
老实说,相比Prism的执行过程,MvvmCross的确实有点绕。不过,它帮你做了好几件任何App开发可能都需要处理的事,包括开机画面、初始化管理、简化的依赖注入、多语言支持,更简单的页面跳转,更简单的数据绑定,另外它还提供了很多其他的插件模块。最关键的是,在MvvmCross的架构下,那些真正复杂难懂的部分,其实都是框架级别的代码,而增加View,ViewModel,Service等这些业务相关的模块的管理,反而比Prism下更简单。所以,如果要我选的话,如果要开发的是一个企业App,功能繁多,需要支持多语言的App,我可能还是会倾向于MvvmCross。我也喜欢Prism的优雅,简洁。真心希望Prism未来能提供更多方便使用的插件,当然,也许只是我孤陋寡闻,果真如此的话就求之不得了!
BTW,不知道为什么,在我本机的iOS模拟器中,升级到iOS 10以后,MvvmCross的iOSApp运行都会闪退,感觉是MvvmCross的bug,希望能尽快有人fix。Prism的iOS项目运行没有任何问题。如果谁知道原因,也请不吝赐教,谢谢!
Update 1:
在MvvmCross的issue tracker新建了一个issue,描述了这个crash的问题:https://github.com/MvvmCross/MvvmCross/issues/1452
Update 2:
上面提到的iOS debugging MvvmCross app crash的问题已经解决了,我删了模拟器里所有以前部署的app,再次debug就可以运行了,很神奇。怀疑是不是,以前的某个app部署过程出错了,然后,后续部署的app和以前有问题的这个app冲突了。不过,至少咱有活路了不是?
Update 3:
免费附赠两行脚本,当Xamarin iOS app调试出错时,如何查看iOS模拟器的device log呢?只需要在MacOS里起一个terminal,执行下面的两条命令:
# list all device's device codes
instruments -s devices
# view latest log of a specific device
tail -f ~/Library/Logs/CoreSimulator/<DEVICE_CODE>/system.log
Prism vs MvvmCross的更多相关文章
- 老司机学新平台 - Xamarin Forms开发框架二探 (Prism vs MvvmCross)
在上一篇Xamarin开发环境及开发框架初探中,曾简单提到MvvmCross这个Xamarin下的开发框架.最近又评估了一些别的,发现老牌Mvvm框架Prism现在也支持Xamarin Forms了, ...
- 老司机学新平台 - Xamarin Forms开发框架之MvvmCross插件精选
在前两篇老司机学Xamarin系列中,简单介绍了Xamarin开发环境的搭建以及Prism和MvvmCross这两个开发框架.不同的框架,往往不仅仅使用不同的架构风格,同时社区活跃度不同,各种功能模块 ...
- 老司机学Xamarin系列总目录
Xamarin开发环境及开发框架初探 Xamarin Forms开发框架二探 (Prism vs MvvmCross) Xamarin Forms开发框架之MvvmCross插件精选 Xamarin开 ...
- [Xamarin]我的Xamarin填坑之旅(一)
一想到明天是星期五,不对,是今天,心里就很激动,毕竟明天没课.激动之余,来写一篇博客,记录一下最近踏坑Xamarin开发校园助手APP的一些事儿.也许更像是一篇流水账. 在扯Xamarin之前,有必要 ...
- 基于Prism.Windows的UWP开发备忘
以前做UWP开发都是使用MvvmLight,主要是简单易上手,同时也写了很多MvvmLight的开发系列文章: UWP开发必备以及常用知识点总结 UWP开发之Mvvmlight实践九:基于MVVM的项 ...
- Xamarin+Prism开发详解六:DependencyService与IPlatformInitializer的关系
祝各位2017年事业辉煌!开年第一篇博客,继续探索Xamarin.Forms… 为什么我做Xamarin开发的时候中意于Prism.Forms框架?本章为你揭晓. 实例代码地址:https://git ...
- Xamarin+Prism开发详解五:页面布局基础知识
说实在的研究Xamarin到现在,自己就没设计出一款好的UI,基本都在研究后台逻辑之类的!作为Xamarin爱好者,一些简单的页面布局知识还是必备的. 布局常见标签: StackLayout Abso ...
- Xamarin+Prism开发详解四:简单Mac OS 虚拟机安装方法与Visual Studio for Mac 初体验
Mac OS 虚拟机安装方法 最近把自己的电脑升级了一下SSD固态硬盘,总算是有容量安装Mac 虚拟机了!经过心碎的安装探索,尝试了国内外的各种安装方法,最后在youtube上找到了一个好方法. 简单 ...
- Xamarin+Prism开发详解三:Visual studio 2017 RC初体验
Visual studio 2017 RC出来一段时间了,最近有时间就想安装试试,随带分享一下安装使用体验. 1,卸载visual studio 2015 虽然可以同时安装visual studio ...
随机推荐
- HDU 4465 - Candy(概率与数学优化)
2012成都Regional的B题,花了一个小时推出了式子,但是搞了好久发现都控制不了精度,后来突然想到组合数可以用log优化,改了之后就AC了 比较水的概率题 #include <stdio. ...
- [CSS] Make element not selectable
.noselect { -webkit-touch-callout: none; /* iOS Safari */ -webkit-user-select: none; /* Chrome/Safar ...
- Java编程思想第四版*第七章*个人练习
欢迎加群:239063848 成团的笔记:该组仅用于技术共享和交流,问题和答案公布 潘基聊天.禁止广告.禁止招聘-- 练习1:(2)创建一个简单的类.第二个类中,将一个引用定义为第一个类的对象.运用惰 ...
- mysql my.ini 详解
linux下mysql配置文件my.cnf详解[转] basedir = path 使用给定目录作为根目录(安装目录). character-sets-dir = path 给出存放着字符集的目录 ...
- Java基础知识强化之IO流笔记40:字符流缓冲流之特殊功能 [ newLine() / readLine() ]
1. 字符缓冲流的特殊方法 BufferedWriter: public void newLine():根据系统来决定换行符 BufferedReader: public String readLin ...
- SoundPool没有声音的问题
在项目中需要播放一个提示,很短的一个声音,Android中播放声音有两种方式:MediaPlayer和SoundPool.相对来说SoundPool比较轻量级一些,多用在播放比较短急的声音,Media ...
- 转:Oracle EBS FND User Info API
转自:http://www.cnblogs.com/quanweiru/p/3775635.html 1. 与用户信息相关API PKG. --和用户处理有关的API FND_USER_PKG; -- ...
- javascript实现可编辑的下拉框
曾经遇到过一个需求的情况是这样的,我们提供给用户的输入框的可选择项只能满足用户的大部分情况的选择,但是有时候会遇到一些用户想要输入的数据是下拉项中所没有的,而用户不希望改变下拉项为输入框模式,需要说如 ...
- maven搭建个人仓库
Maven环境搭建: 本地仓库+maven运行环境+构建项目 1.搭建nexus 本地仓库 1)拷贝jdk1.6和tomcat62)配置端口为8010 (端口自行定义,只要下面各处一致即可)3)复制n ...
- xml_03
1.xml 2.对于XML文档的约束 |-DTD <!DOCTYPE 根元素 [ <!ELEMENT 元素名 (xx)> <!ATTLIS ...