博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Windows Phone 性能优化(一)
阅读量:5072 次
发布时间:2019-06-12

本文共 7227 字,大约阅读时间需要 24 分钟。

 

在实际的项目开发过程中,应用的性能优化是一个永恒的话题,也是开发者群里最常讨论的话题之一,我在之

前的公司做 wp项目时,也遇到过性能的瓶颈。当页面中加载的内容越来越多时,内存涨幅非常明显(特别是

一些壁纸类的应用,当用户向下滑动列表加载更多),当内存超过 120MB 有些机型的发热明显,如果内存继

续上涨,发热事小,内存泄露后,系统会直接关闭应用。

 

在 wp 系统中自带的 ListBox 等控件也提供内存虚拟化,但是如果用得不好,可能会破坏虚拟化。

微软 MSDN

 

MSDN 部分摘抄:

Silverlight中,为了将数据显示给用户,我们需要加载数据和绑定数据,但是哪个会导致性能问题呢?答案是:根据你的数据类型以及界面(UI)的复杂性而定。

通常,加载数据可以在UI线程或者后台线程中实现,数据存在的形式也不经相同,有的序列化为二进制数据,有的序列化为XML文件,有的则是图片形式存在等等。而数据绑定又有三种不同的绑定形式:一次绑定(One  Time)、单向绑定(One Way)和双向绑定(Two  Way)。

 

这里简单介绍下什么是VSPVirtualizingStackPanel

将内容排列和虚拟化在一行上,方向为水平或垂直。“虚拟化”是指一种技术,通过该技术,可根据屏幕上所显示的项来从大量数据项中生成user  interface (UI) 元素的子集。仅当 StackPanel 中包含的项控件创建自己的项容器时,才会在该面板中发生虚拟化。 可以使用数据绑定来确保发生这一过程。 如果创建项容器并将其添加到项控件中,则与 StackPanel 相比,VirtualizingStackPanel 不能提供任何性能优势。

VirtualizingStackPanel ListBox 元素的默认项宿主。 默认情况下,IsVirtualizing 属性设置为 true。当 IsVirtualizing 设置为 false 时,VirtualizingStackPanel 的行为与普通 StackPanel 一样。

我们可以将VSP理解为当需要时,VSP会生成容器对象,而当对象不在可视范围内时,VSP就把这些对象从内存中移除。当ListBox很想当大数据量的项目时,我们不需要将不在可视范围中的对象加载到内存中,从而解决了内存的问题。另外VSP有一个属性设置缓存表示形式,默认设为Standard。当我们需要循环显示,可以将其设置为Recycling

ListBox中使用VSP来进行数据虚拟化时,我们需要注意以下几点:

   确保在DataTemplate 中的容器(如Grid)大小固定

   在数据对象可以提供相应值时,尽量避免使用复杂的转换器(Converter

  不要在ListBox中内嵌ListBox

 

加入动画验证 ListBox 项的动态创建和删除

为了验证 ListBox 在列表部分内容滑入、滑出屏幕可视区域时,内容是动态创建和删除的,我在 ListBox 的

ItemTemplate 模版中给每个项加入动画,并且通过  <EventTrigger RoutedEvent="StackPanel.Loaded">

进行触发,当滑动列表时,运行效果:

 

当加载 200条数据时,看到内存检测才 22MB,实际如果没有虚拟化,内存可达150MB 以上。

 

 Demo 的部分代码介绍(在接下来的 文章二 的列表加载是相似的逻辑)

1)首先自定义一个 News 类,包含两个字段,一个 Title ,一个 Picture:

public class News : System.ComponentModel.INotifyPropertyChanged    {        string title;        public string Title        {            get            {                return title;            }            set            {                if (value != title)                {                    title = value;                    NotifyPropertyChanged("Titlte");                }            }        }        string photo;        public string Photo        {            get            {                return photo;            }            set            {                if (value != photo)                {                    photo = value;                    NotifyPropertyChanged("Photo");                }            }        }        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;        public void NotifyPropertyChanged(string propertyName)        {            if (PropertyChanged != null)            {                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));            }        }    }
View Code

2)在工程的根目录下创建一个 Image 文件夹,里面放 10张示例新闻配图。

3)MainPage 中只需要关注两个控件,一个是 页面顶部显示内存的:

 

第二个是显示新闻列表的:

它的默认 ItemsPanelTemplate 是 VirtulizingStackPanel。在有些交换中,需要去掉 ListBox

的虚拟化功能,就可以把这个 VirtulizingStackPanel 换成 StackPanel

 

在 ListBox 的 ItemTemplate 中放一个触发器,当 StackPanel 触发 Loaded 事件的时候,播放预定义动画(在 Blend 中设计的动画)。

从而可以判断每次当 ListBox 的 Item 创建完成后,就会触发一次这个动画。StackPanel 中放一个 TextBlock 和一个 Image,用来

显示 News 的 Title 和 Picture 字段。

 

ListBox 的完整 xaml:

View Code

 

4)创建示例新闻,通过 Random 类控制每条新闻的 标题长度和 配图是 随机的:

#region 示例数据源        Random rd = new Random();        void LoadNews(int Length)        {            for (int i = 0; i < Length; i++)            {                NewsList.Add(new News                {                    Title = "不过需要注意的是——为了彰显自己对Kevin Kelly多年追随,而非跟风所为,                              你最好能够熟记百度百科上有关他生平的介绍,如果记不全也没关系,知道《黑客帝国》                               主创人员都被要求看《失控》这件事,就足以应付一干人等了。".Substring(0, rd.Next(20,100)),                    Photo = "/Images/0" + rd.Next(0, 10) + ".png"                });            };        }        #endregion

 

在 MainPage 中自定义一个 DispathcerTimer 对象,每隔两秒,把当前应用所占的内存打印到顶部:

#region 内存使用情况        static System.Windows.Threading.DispatcherTimer dispacherTimer;        void CheckMemory()        {            dispacherTimer = new System.Windows.Threading.DispatcherTimer();            dispacherTimer.Interval = TimeSpan.FromSeconds(2);            dispacherTimer.Tick += new EventHandler(dispacherTimer_Tick);            dispacherTimer.Start();        }        static string total = "DeviceTotalMemory";        static string current = "ApplicationCurrentMemoryUsage";        static string peak = "ApplicationPeakMemoryUsage";        static long totlaBytes;        static long currentBytes;        static long peakBytes;                void dispacherTimer_Tick(object sender, EventArgs e)        {            // 获取设备的总内存            totlaBytes = (long)Microsoft.Phone.Info.DeviceExtendedProperties.GetValue(total);            // 获取应用当前占用内存            currentBytes = (long)Microsoft.Phone.Info.DeviceExtendedProperties.GetValue(current);            // 获取内存占用的峰值            peakBytes = (long)Microsoft.Phone.Info.DeviceExtendedProperties.GetValue(peak);            txtMemory.Text = string.Format("当前:{0:F2}MB;  峰值:{1:F2}MB;  总:{2:F2}MB;",                         currentBytes / (1024 * 1024.0), peakBytes / (1024 * 1024.0), totlaBytes / (1024 * 1024.0));        }        #endregion

 

5)初始化 MainPage 中的 列表等操作:

ObservableCollection
NewsList = new ObservableCollection
();//{ get; set; } // 构造函数 public MainPage() { InitializeComponent(); this.Loaded += MainPage_Loaded; } void MainPage_Loaded(object sender, RoutedEventArgs e) { // 给 NewsList 加载两百条新闻 LoadNews(200); // 设置当前页面的上下文 this.DataContext = NewsList; // 开始打印内存 CheckMemory(); }

 

 

运行上面的代码,看到顶部的内存占用很少。当把 VirtualizingStackPanel 换成 StackPanel 时:

变成:

 

运行工程,靠,内存直接上 200MB,是之前的约 20倍,如果在 512MB 的设备上,会直接被系统杀掉。

并且当滑动时,也不会触发 Loaded 的动画:

 

 

当然,如果 ListBox 使用不当也会破坏它的虚拟化,比如有的项目中,把 ListBox 放在 一个 ScrollViewer

中,虚拟化就不起作用了,确实有些这种情况,并且开发者并没有注意到这个问题所在。比如有的朋友在

ScrollViewer 里,上面放一个 幻灯片,下面放一个 ListBox(或者 ItemsControl 控件):

 

 

因为 ListBox 的虚拟化功能不被破坏是需要一定条件的,在后面的文章会介绍如何如何模拟 ListBox 实现虚拟化功能,

其实原理很简单,就是在列表中的项,不在屏幕的可视区域内时,动态的隐藏或者删除,当滑动回来时,再重新

显示或创建。

 

转载于:https://www.cnblogs.com/hebeiDGL/p/3410188.html

你可能感兴趣的文章
用OGRE1.74搭建游戏框架(三)--加入人物控制和场景
查看>>
转化课-计算机基础及上网过程
查看>>
android dialog使用自定义布局 设置窗体大小位置
查看>>
ionic2+ 基础
查看>>
互联网模式下我们更加应该“专注”
查看>>
myeclipse集成jdk、tomcat8、maven、svn
查看>>
查询消除重复行
查看>>
Sand Making Plant Produced by Red Star
查看>>
Win 10 文件浏览器无法打开
查看>>
HDU 1212 Big Number(C++ 大数取模)(java 大数类运用)
查看>>
-bash: xx: command not found 在有yum源情况下处理
查看>>
[leetcode]Minimum Path Sum
查看>>
内存管理 浅析 内存管理/内存优化技巧
查看>>
hiho1079 线段树区间改动离散化
查看>>
【BZOJ 5222】[Lydsy2017省队十连测]怪题
查看>>
第二次作业
查看>>
【input】 失去焦点时 显示默认值 focus blur ★★★★★
查看>>
Java跟Javac,package与import
查看>>
day-12 python实现简单线性回归和多元线性回归算法
查看>>
Json格式的字符串转换为正常显示的日期格式
查看>>