博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

我在这个系列的第一篇就讲到了导航的问题,不过可能有些问题还没讲明白,所以这里再写一篇关于导航的博客。

这里有两个问题:

1.为什么在调用Frame.Navigate方法的时候不能直接传简单类型以外的对象?

2.为什么页面每次back的时候都会初始化页面?

我先来讲下VS的项目模版,在我们建立项目的时候如果选的不是空白项目,VS自动会创建一个包含Common文件夹的项目,而每个页面都继承自LayoutAwarePage,LayoutAwarePage帮我们做了很多必要的处理,看里面的代码你会发现LayoutAwarePage重写了NavigateTo和NavigateFrom方法,而多了两个LoadState和SaveState两个虚方法。这样我们几乎可以忘了NavigateTo和NavigateFrom方法了,直接用LoadState和SaveState方法就行了。这里还得说下为什么LayoutAwarePage重写了两个方法,看LayoutAwarePage的代码我们可以发现,LayoutAwarePage在NavigateTo方法里面做了数据恢复的处理,当处理完了会调用LoadState方法,并把原来保存的数据传给LoadState方法,这里的数据只有当back的时候才会有,因为只有在back的时候才会需要恢复数据。LayoutAwarePage在NavigateFrom方法里面做了数据保存的处理,当从当前页导航到其他页面的时候就会保存你的数据,具体保存什么数据是需要你自己处理的。

然后我们再看下项目模版是如何帮我们恢复好保存数据的.

我们所有经过SaveState方法保存的数据都是SuspensionManager这个类来处理的,当程序启动的时候,会在APP类的OnLaunched方法里面会调用 SuspensionManager.RegisterFrame初始化SuspensionManager,如果程序是从挂起状态恢复的那么还会调用SuspensionManager.RestoreAsync方法来恢复数据。而当程序处于挂起状态的时候,会在APP类的OnSuspending方法里面调用SuspensionManager.SaveAsync来保存数据(数据的保存是以文件形式保存的)。

到这数据的恢复和保存已经讲完了,然后我要将下前面提到的第一个问题,为什么在调用Frame.Navigate方法的时候不能直接传简单类型以外的对象?

问题就出在SuspensionManager.SaveAsync方法里面,因为这个方法会调用Frame.GetNavigationState方法,这时候如果你页面传递的参数是复杂对象,那么直接crash,因为Frame.GetNavigationState无法序列化你的对象,就算你已经为你的类加上[DataContract]和[DataMenber]标记也没用,对于这个问题我也问了微软的相关技术人员,给我的答复是在传递对象的时候把对象先序列化成字符串,然后再在使用的时候反序列化成对象,这不是坑爹的吗!!!

 

下面讲上面提及的第二个问题,为什么页面每次back的时候都会初始化页面?

对于这个问题我是这么认为的(纯属个人观点,有臆测成分,欢迎拍砖)。

我觉得之所以每次back的时候页面都会初始化,很大程度上是从内存的使用率来考虑的。我们从商店下载的APP,很大部分的APP都是以图片来展示内容的,由于平板的屏幕肯定比手机大,那同时显示的图片数量势必会比较多,就算你启用了虚拟化技术还是会有这个问题的,一张图片的体积差不多能顶得上一部小说了,而一个页面同时显示较多的图片势必会占用较多的内存,而一个APP会有很多的页面,如果每一个页面都这样的话那么一个APP所占用的内存将会有多大!现在当从当前页导航到其他页面的时候我认为系统会把原来页面释放掉以节约内存开销,这样你的APP配合数据虚拟化技术在内存的开销上始终会处于一个稳定的状态(我们目前开发的APP内存基本维持在60-80MB之间)。

另外我要说下什么是数据虚拟化技术,数据的虚拟化是列表类控件的专有的。假如你有1000条数据作为数据源给列表控件,如果你没有启用数据虚拟化(默认是开启的),那么列表控件将会加载1000个item,每一个item都会占用内存资源,可想而知你的app要占用掉多少的资源,其实不只是内存的开销,还有就是在你绑定数据源的时候出现卡的现象(因为列表控件要一下子初始化1000个item,不卡才怪!)。幸好目前的gridview,listview,listbox,flipview都默认启用数据虚拟化的,这样你有1000条数据的情况下,系统只要初始化10条或者更少的item(具体初始化多少条系统计算的),这样一个减少了内存开销,还一个是加快了列表控件的初始化速度。

数据的虚拟化其实是依靠列表控件的容器(ItemsPanel)来实现的,这些列表控件默认的容器都是从VirtualizingPanel继承过来的,在win8种WrapGrid和VirtualizingStackPanel都是支持数据虚拟化的容器。我们自己也是可以自定义支持虚拟化的容器的,不过这个过程是很复杂的。

目前我用了一款社交类的APP,我可以确定这个APP没用启用虚拟化技术,它有分页功能,当我一直往下加载页面的时候内存蹭蹭的往上涨,当我大概浏览到100页的时候内存占用已经有1G了,你没看错,是1G。

 

本篇到此!预告下下一篇

Window 8开发疑难杂症(四)——数据库