欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > 内容正文

Windows Phone 性能优化(二)

来源: 开发者 投稿于  被查看 27173 次 评论:165

Windows Phone 性能优化(二)


 

这篇文章的 demo 是在 (一)的基础上进行的调整,逻辑基本相似。

 

为了实现自定义的虚拟化,把上一篇文章的 ListBox 换成 ScrollViewer + ItemsControl,这样组合在实际的项目

中又是还是会用到的,比如,如果我们需要对 ScrollViewer 进行很多的控制,比如获取它的“滑动”事件,ScrollViewer

中在放置其它控件,或者直接定制它的样式等等(当然可以通过 VisualTreeHelper 也可以获取 ListBox 中的 ScrollViewer)。

 

ListBox (继承自 ItemsControl)内部的实现就是封装了 ScrollViewer + ItemsControl 控件,在本 demo 中,使用的组合为:

            
                
                    
                        
                            
                            
                        
                    
                    
                        
                            
                                
                                                                   
                            
                        
                    
                
            


在上一篇 demo 的基础上,当加载 200条数据时,在 1G 的模拟器上运行时,内存占用竟达到 200+MB

如果在 512MB 的模拟器上,还没加载数据完成,应用就崩溃了:

 

优化算法

下面 demo 的原理很简单,就是当列表中的项,在屏幕内的时候,把它的 Visibility 设置为 Visibility.Visible,

当在屏幕外面的时候,设置为 Visibility.Collapsed; 逻辑很简单,但是对内存的占用明显下降。但是,为了用户

体验,也就是如果当用户滑动列表到屏幕的地方,它的项目没有及时的显示,在用户的角度看,是会非常沮丧的,所以

需要一个算法检查当前列表中的项是否在屏幕内。

思路:

 

 

 

关于这个 demo 其它部分的代码请参考上一篇文章。

1)首先在 xaml 页面放一个按钮,如上图所示,当应用加载完成时,默认不错任何处理,当点击 “虚拟化” 按钮时,

触发自定义虚拟化方法,页面中的 xaml:

           


相应的 C#:

        
          Button_Tap(= 


2)当点就按钮后,首先获取列表中,所有由 DataTemplate 中的 StackPanel 复制的每一项。因为 ListBox 继承自 ItemsControl,

并且它们 ItemContainerGenerator 属性的 ContainerFromIndex(int index) 方法可以获取列表中的指定的 Item,然后在通过

VisualTreeHelper 的静态方法,获取模版产生的 StackPanel。全部的代码:

        
            Dictionary<, StackPanel> dic =  Dictionary<, StackPanel> height_sum =  ( i = ; i < listbox.Items.Count; i++
                FrameworkElement fe = listbox.ItemContainerGenerator.ContainerFromIndex(i) = FindFirstElementInVisualTree<StackPanel>
// 30 为模版中父容器的 margin-top
height_sum = height_sum + sp.ActualHeight + // 很重要,如果不为父容器指定固定高度,当子元素隐藏后,父容器高度变为0px sp.Height = Observable.Interval(TimeSpan.FromSeconds(.)).ObserveOnDispatcher().Subscribe((_) => ( keyValue (((scrollViewer.VerticalOffset - ) > keyValue.Key || keyValue.Key > (scrollViewer.VerticalOffset + ].Visibility =].Visibility =].Visibility =].Visibility = T FindFirstElementInVisualTree<T>(DependencyObject parentElement) count = (count == ) ( i = ; i < count; i++ child = (child != && child result = FindFirstElementInVisualTree<T> (result !=


当加载 200 条新闻的时候,运行工程效果:

  

上面算法是每 0.5秒 遍历一下 Dictionary 的 keys,为了直观就没有再优化。比如每次遍历的时间,

屏幕的可视区域等。

 

默认运行时,内存占用 208MB 效果:

 

单击按钮后,当上下滑动的时候,可以看到延迟显示的 item,内存占用减少了不少:

 

 

另外,我想到可以使用 快速排序 的算法方法,可以更快找到新滑动到屏幕里的 Item,之前在屏幕外的 Item

如果还在屏幕外,则跳过,等等。关于如何优化上面算法这里就不在多讲了。因为项目只是在介绍减少内存的

思路,所以没有考虑在应用中如何在“加载更多..”时,如何再次添加新 item 等等实际交互。

 

还有就是关于 Reactive Extension 相关类库(已经集成在了 WP8 的sdk 中)的使用,这里也不过多介绍,它

确实是一个神奇的东西,园子里有朋友写过相关的文章,我前段时间也翻译了一下(译文链接),稍后会整理

更多关于 Rx 的文章。这里使用 Observable  作为计时器,当然也可以自定义 Timer ,不过感觉 Observable 用起来

更加方便。

 

上面代码中:)).ObserveOnDispatcher().Subscribe((_) =>

 

 

 

 

相关频道:

用户评论