【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方面的经验和大家分享。时间不早了,洗洗睡吧

猜你喜欢

转载自leyteris.iteye.com/blog/1614211