欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【WP开发】浅谈开发中一些性能优化的要点

程序员文章站 2022-04-30 10:01:59
...

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