【WP开发】浅谈开发中一些性能优化的要点
简要的分享下WP开发中碰到的一些性能优化的要点。
一、内存泄漏
首先一个很重要的是关于GC,如果使用IOC+MVVM开发模式,很可能导致操作时view得不到释放,造成内存泄露。
检测GC:我们要在这里重载析构函数帮助我们了解view是否被销毁。在xaml后台代码中加入下面代码:
~BindMobilePage() { CommonHelper.Log("Finalizing " + this.GetType().FullName); }
可以直接检测view 在退出时是否被销毁。
接下来如果我们发现没有被销毁,我们就要采取对策了
一种情况是vm还对当前view有依赖。我们可以在OnRemovedFromJournal中销毁它;
OnRemovedFromJournal这个方法事实上是view被弹出栈顶时调用的方法;
我们可以这样:
protected override void OnRemovedFromJournal(JournalEntryRemovedEventArgs e) { Messenger.Default.Unregister<bool>(this, MessageToken.MessageListChanged); this.DataContext = null; base.OnRemovedFromJournal(e); }
注意这里其实就是将view依赖的vm与view解绑,这样就能安全释放view。
Messenger.Default.Unregister<bool>(this, MessageToken.MessageListChanged);这个语句很重要,如果vm在init时在Messenger中注册了观察者,系统默认不会将这个vm关联的view销毁,所以我们可以在这里对他进行销毁。当然这样的Messenger销毁我们一般也可以直接写在vm里以保持生命周期的统一性。
如下:
public void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e) { if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Back) { Messenger.Default.Unregister<bool>(this, MessageToken.MessageListChanged); this.StoryList = null; this.PersonList = null; this.UserDetail = null; GC.Collect(); } }
一般情况在NavigationMode为back时候就是view销毁时机,我们可以在这里进行观察者的解绑
注意这里StoryList = null语句,一般的List类型是不用这么写的,但是对于像这个list是ObservableCollection时,我们就要手动对它释放,(这个List也是观察者模式,view的ListBox一直有依赖关系,所以很可能会导致view得不到释放)系统对他的释放很可能是不彻底的。
public ObservableCollection<PostViewModel> StoryList
其他的话还有WebBrowser如何和vm挂接也很可能会导致view得不到释放。比如以前我想所有逻辑代码全部写在vm中所以这样写:
public class ImageViewModel : ViewModelBase, INavigatedViewModel//, INavigation { public void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { Uri uri = e.Uri; string src = NavigationHelper.GetQueryString(uri, "src"); var html = @"<html> <head> <title>Image</title> </head> <body style='width:100%; height:100%; background:#fff; text-align:center; display:table;' > <img src='{0}' alt='picture' style='width:98%; margin:auto 0; vertical-align: middle; display:table-cell;'/> </body> </html>"; var htmlString = String.Format(html, src); Messenger.Default.Send<string>(htmlString, MessageToken.ImageHtmlString); } public void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e) { } }
并在后台文件中:
public ImagePage() { InitializeComponent(); Messenger.Default.Register<string>(this, MessageToken.ImageHtmlString, (string html) => { var size = App.Current.RootVisual.RenderSize; WebBrowser.Width = size.Width; WebBrowser.Height = size.Height - 10; WebBrowser.Background = new SolidColorBrush(Colors.White); WebBrowser.LoadCompleted += WebBrowserLoadCompleted; WebBrowser.NavigateToString(html); }); }
导致这个view不论如何都释放不了。不管是销毁时取消观察还是。。。
就是一味的追求解耦。。。其实只要在view 的后台中直接操作就够了,完全能够自动释放。
二、ListItem的Cell渲染问题
首先item必须保持能够虚拟化。这个问题不提了,很多网上的教程中有。
我想说的只有一点:最好别用converter,当时要做一个对item字数截取的功能,每条item都是140中文字以内,将这个操作写成了converter方法,刚开始还不错,因为自己的测试机是性能比较高的lumia,结果把app放到别人机子上一跑,感觉超慢。
由于wp的虚拟化事实上我们滑动时系统一直在就DataBind的数据进行填充。而每次填充converter都会被执行一次,这个cut的方法每次渲染都会去执行,性能极差。
我的建议是对于datasource外面做一层包装,对数据做一次处理之后在返回给view层,这样每次系统拿data时候就直接拾取就可以了,不用converter进行转换了,当然这种情况只对于静态的datasource,动态的还是要用converter的,不过尽量要少用。
三、PivotPage到DetailPage的页面跳转性能问题
当这个PivotPage里面的没有PivotItem都是可进入的ListBox时,点进去会有很大的性能问题,会感觉从detail回来的时候特别的慢,多则有4到5秒的时间。。。用户完全受不了。
对于这个问题的优化:
第一:如果Pivot的content都是通过网络加载的话,保证分页加载以及PivotItem的懒加载。
所谓懒加载其实就是当用户滑动到那个Item的时候才开始加载data:
<toolkit:LockablePivot x:Name="FeaturePivot" Title="{Binding Title}" Foreground="{StaticResource PhoneAccentBrush}"> <toolkit:LockablePivot.RenderTransform> <CompositeTransform /> </toolkit:LockablePivot.RenderTransform> <i:Interaction.Triggers> <i:EventTrigger EventName="SelectionChanged"> <cmd:EventToCommand Command="{Binding ChangeSelectionCommand}" CommandParameter="{Binding ElementName=FeaturePivot}" /> </i:EventTrigger> </i:Interaction.Triggers> ............................................. <toolkit:LockablePivot/>
在xaml中如上代码,绑定一个ChangeSelectionCommand的Command,再在vm中
public void ChangeSelectionAction(object sender) { Pivot featurePivot = sender as Pivot; switch (featurePivot.SelectedIndex) { case 0: ////// } }
类似于上面的代码,这样就可以实现懒加载。
其实这样是不够的,当pivot的几个item充斥了data之后内存会飙升,这个时候在从detail载入时就会异常的慢,
方案是这样的,我们在切换到那个item的时候将其他item的data缓存后在清空,下次进来从缓存里拿。
但这样会导致切换item时用户体验稍差。我的建议是当点击的当前pivotitem下的ListItem时在将其他PivotItem的data清空。
这样呢可以保证用户体验。
好吧。。。其他的性能方面的提升以后再聊了,另外我已经开始在做iOS的开发了,以后会有iOS方面的经验和大家分享。时间不早了,洗洗睡吧
上一篇: 微软支招:如何让WP应用脱颖而出
下一篇: 如何给category添加属性