WP7 性能优化系列 (2)
1 Converter
在用数据绑定的时候应该尽量少用Converter,因为Converter对UI线程是一个不小的开销:运行时需要从Silverlight转到处理代码,然后执行Converter再把结果返回给Silverlight。如果converter做了大量的工作,那么UI线程将会被明显阻塞。
替代方案:尽量把数据转换的操作放到对象类或者viewmodel中,虽然讲转换过程放到对象类中会破坏封装,但却能大大的提高程序的性能。
2 DataTemplates
数据模板的问题涉及到ListBox等集合面板的渲染速度,如果集合面板中的项都用到了相同的数据模板,当用户滑动屏幕展示其他项时ListBox只需要把缓存的模板拿过来然后把数据填充进去即可,不需要重新计算和渲染。这一点和系列一中的第二点相似。
除了上面说的内容,在设计数据模板的时候应尽量减少容器的嵌套,如Grid中嵌套Grid、Stackpanel,Grid的复杂度决定了它对性能的消耗,所以设计数据模板时尽量用简单的Canvas或者StackPanel等轻量级的容器,稍微负责的布局尽量用一个Grid结合行、列的定义。
3 绑定属性
在支持绑定的属性的get方法要尽量避免使用逻辑处理,如:
public int Rating
{
get
{
<read from database>
- or -
<read from IsoStore>
- or -
<parse out some XML>
- etc -
}
}
这种写法在绑定数据时需要处理数据逻辑,阻塞UI
4 关闭BackgroundWork
后台执行的线程会影响UI线程,只是后台线程占有很小的时间片,如下:
当有大量的后台线程处于活动时仍然会占据大量的CPU时间从而对UI线程造成明显的阻塞,因为UI线程和其它线程处理执行时间上的差别以外没有任何其它优势,处于同一个优先级上。
当一个时间片执行结束时,它要通知所有其它的线程来完成最后的工作,所以后台线程越多这个结束过程占用时间就越长。
综上所述,除了尽量减少后台线程的数量和及时关闭后台线程以外,应该尽可能的使用线程池管理线程来避免所有的线程同时争抢运行。
5 使用ListBox显示大量数据滑动时出现空白屏幕的情况,原因是虚拟化。在滑动时ListBox的虚拟化机制需要先计算出新数据占用的空间,在计算的时间里显示空白屏幕。
禁用ListBox的方式是重新定义ListBox的项目容器模板,如下:
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel>
</StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
这样做解决了空白屏幕的问题,但是也带来了副作用:
- 页面启动时间增加,现在容器需要准备好所有项时才显示出来,而不是先显示空白屏幕再填充内容,所以在增加了流畅性的同时占用跟多的启动时间
- 现在容器里会容纳所有的项,增加内存开销,不过可以在程序里控制列表显示的数量
6 以下技巧和窍门参考文章: http://timheuer.com/blog/archive/2010/09/16/windows-phone-7-developer-tips-and-tricks.aspx
² 相比Pivot来说,Panorama控件视觉效果好一些,但是启动速度慢
² 可以设置Pivot的背景图片,但是不会获得滑动时的视差效果
² 一定要严格控制Pivot和Panorama的item数量,当有大量图片和item时内存将增长的很快
² 仅仅一张30k的压缩JPEG图片在运行时也会被解压缩到占用好几M内存
² 需要自定义Pivot and Panorama的Header样式
² WP7中大于2000*2000像素的UI控件将会被截掉超出部分
² 当Pivot的items为空时不可以设置SelectedIndex,会出现异常。
² A slideshow app in 5 minutes: Pivot with null Header and Title and item headers. Beware memory use though. 不太明白这个是啥意思
² 不要使用panorama&Pivot创建向导界面,用户体验很差
² 在布局上一定要注意,比如容器的选择、尺寸的设定、大小的自适应等会严重影响性能
² 尽量选择延迟加载控件和页面,如果给Panorama控件加10亿个item那永远也不会加载完成
² 建议使用PerformanceProgresBar而不是系统自带的process indicator,性能方面的考虑,参考这里 http://www.jeff.wilcox.name/2010/08/progressbarperftips2/
² 如果应用程序确实启动很快那么可以考虑去掉启动页面(SplashScreen)
² 在模拟器上运行的程序效果不能代表在真机上的运行效果,硬件能力的差别是不可忽视的
² 将图片的属性设置成Content而不是Resources可以提高启动速度
² 将Panorama的背景图属性设置为Resource而不是Content可以提高启动速度(区别于上一条)
² 应用程序的内存占用不得超过90M,当然在内存大于256MB的机器上可以多用一些,但是大于90M时不会通过Markedplace的验证
² 获取内存占用:
n long deviceTotalMemory = (long)DeviceExtendedProperties.GetValue("DeviceTotalMemory");
n long applicationCurrentMemoryUsage = (long)DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage");
n long applicationPeakMemoryUsage = (long)DeviceExtendedProperties.GetValue("ApplicationPeakMemoryUsage")
² GPU加速线程应该保持60fpt的刷新频率,参考http://www.jeff.wilcox.name/2010/07/counters/ 和http://blogs.telerik.com/blogs/posts/10-12-13/ui-vs-compositor-demystifying-the-main-windows-phone-7-os-threads.aspx
n Debug时查看帧速
#if DEBUG
Application.Current.Host.Settings.EnableFrameRateCounter = true;
Microsoft.Phone.Shell.SystemTray.IsVisible = false;
#endif
² UI线程卡住时,GPU加速线程也会被卡住,后台线程会执行
² 普通Silverlight应用程序的分析功能在WP7上并不具备,所以无法测量普通的WP7应用占用CPU的情况
² 使用DispatcherTimer将会影响你的电池续航能力
² 你可以设置Pivot的Foreground属性来设置title和header字体颜色
² 为了提高性能,不推荐在Pivot和Panorama控件中放入地图控件,可以打开新页面显示
² 尽量用style设置文本的字体和大小
² 为了优化用户体验,Panorama和Pivot的item需要左右有12像素的空白,这也是默认设置。如果设置了margin为0将使用户体验很糟糕
² 填充比率很重要,它的值是1表示一个屏幕渲染的内容,这个值最好不要超过2.5,即要显示的内容超过2.5屏
² 不需要设置背景色的地方就不要设置背景色,背景色也会影响性能
² 需要倾斜效果时请使用这里的behavior http://blogs.msdn.com/b/ptorr/archive/2010/08/11/updated-tilt-effect.aspx,性能方面的考虑
² DataTemplates里不要使用大量的Grid和Stackpanel,尽量用Grid的行和列来布局
² Silverlight的单元测试功能使WP7的单元测试简单快捷,参考http://www.jeff.wilcox.name/2010/05/sl3-utf-bits/
² 只有在必要时才使用Dispatcher.BeginInvoke, 可以看一下关于SmartDispatcher的内容http://bit.ly/axHh36
² 当Panorama的item很宽时设置item的Orientation=Horizontal
² 使用缓存(cache),可以查看vis.settings中缓存了哪些东西
² 在list或是scrollviewer中的项目将会被Silverlight for Windows Phone自动缓存成图片
² 尽量把progress bar的属性IsIndeterminate=“false”,因为设置为true时及时progress bar隐藏时对storyboard来说也会消耗大量的性能来处理
² 在WP7中把网络相关的操作放到后台线程---也许有帮助吧。。。
² 显示Panorama控件时,它所有的item都会被渲染;Pivot则随着显示过程只渲染相邻的item
² 有网络请求时,尽量减少请求的字段数量或改变字段格式来提高性能(例如用json代替xml)
² 当导航到其他页面时,原来的页面还会驻留在内存中,复杂的pivot/panorama页面将会占用大量的内存空间,所以需要在导航控制页面的销毁
² 强烈建议从isolatedstorage load图片之类的数据,因为那里比内存加载的更快
² 用PhoneForegroundBrush, PhoneBackgroundBrush代替"Black" or "White”颜色
² 如果对依赖属性提供了chenged handler,那么对此属性的动画将在UI线程执行,而不会被GPU加速
² 如果控件设置了CacheMode="BitmapCache",那么对它的Opacity做的动画将在GPU加速线程执行
² 可滚动视图自动带有弹跳效果
² 如果抛弃WP7的主题,而且用白色的背景那么就需要为Appbar重新定义样式,否则Appbar将不可见
² 如果使用ObservableCollection绑定了一个集合容器,那么200k的数据量将会使应用很受伤
² Webbrowser在loaded之前不允许使用NavigateToString
² 如果应用程序使用了多个Webbrowser,尽量把这些使用webbrowser的地方整合在一起,使用一个webbrowser,避免加载多个webbrowser
² Panorama是用来当做首页的控件,起导航作用,而不是用作显示大量的数据
² 如果按照规定使用panorama控件那么性能将得到大幅的提升,参见: http://msdn.microsoft.com/en-us/library/hh202915(v=VS.92).aspx
所以请正确使用panorama,即得到了良好的用户体验而又不损失性能