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> 

这样做解决了空白屏幕的问题,但是也带来了副作用: 

  1. 页面启动时间增加,现在容器需要准备好所有项时才显示出来,而不是先显示空白屏幕再填充内容,所以在增加了流畅性的同时占用跟多的启动时间
  2. 现在容器里会容纳所有的项,增加内存开销,不过可以在程序里控制列表显示的数量 

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,即得到了良好的用户体验而又不损失性能

 

posted @ 2012-06-14 15:10  vvGO  阅读(1183)  评论(4编辑  收藏  举报