发现了正在发生的事情 - 同时运行的Accelerometers和VideoBrushes会冻结VideoBrush。要解决此问题,请在启动VideoBrush
之前停止加速度计使用最少的代码(如下所示),它会在应用程序启动VideoBrush后大约2分15秒时可靠地崩溃。这是在使用c#和Xaml的Windows Phone 7.5应用程序的Windows 7模拟器上。如果VideoBrush拉伸也设置为填充等,则会发生这种情况(此时存在Silverlight 1.0错误)
关于我如何得出这个问题的故事,请查看下面的文字答案:)
为什么会这样?我不知道。也许有内存泄漏或什么?值得注意的是 - 这实际上不会使应用程序本身崩溃。你不会弹出任何异常。
重现问题的代码(制作一个名为PhoneApp1的新应用程序并自行试用!):
Xaml代码:
<phone:PhoneApplicationPage
x:Class="PhoneApp1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="False">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Rectangle x:Name="viewfinderCanvas" Width="480" Height="800" >
<Rectangle.Fill>
<VideoBrush x:Name="viewfinderBrush"/>
</Rectangle.Fill>
</Rectangle>
</Grid>
</phone:PhoneApplicationPage>
C#代码:
using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Devices;
using Microsoft.Devices.Sensors;
namespace PhoneApp1
{
public partial class MainPage : PhoneApplicationPage
{
private Accelerometer AccelerometerSensor;
// Constructor
public MainPage()
{
InitializeComponent();
AccelerometerSensor = new Accelerometer();
AccelerometerStartup();
if ((PhotoCamera.IsCameraTypeSupported(CameraType.Primary) == true))
{
viewfinderCanvas.Visibility = Visibility.Visible;
var cam = new Microsoft.Devices.PhotoCamera(CameraType.Primary);
viewfinderBrush.SetSource(cam);
}
}
#region Accelerometer Startup Function
private void AccelerometerStartup()
{
try
{
if (AccelerometerSensor != null)
{
AccelerometerSensor.Start();
}
}
catch (AccelerometerFailedException)
{
}
catch (UnauthorizedAccessException)
{
}
}
#endregion
}
}
下面的原始问题: (下面提到的代码已保留,但由于没有附加加速计,因此无法重现问题)
这是一个有趣的,我保证。
我决定在我的wp7.5 app中添加一个矩形,其fill属性是VideoBrush。我使用了从几个网站找到的代码,并认为一切都很好。直到我注意到摄像机的VideoBrush会冻结...运行它的时间为6到40秒。
令人困惑,我以为我的派遣计时器干扰了相机。将它们注释掉以便它们无法运行并不能解决问题。然后我尝试在应用中停用我的广告。也没有解决它。我禁用了可以在整个应用程序中呈现更新的所有内容(计时器,调度计时器,广告轮播,任何循环),并且它仍然冻结。
我做了同样的事情,甚至将我的设备从计算机上拔下来,因为当我使用设备进行调试时,使用zune open连接到计算机可能会中断事情。仍然没有骰子。
我创建了一个新项目并将其粘贴到VideoBrush代码中,并且无需冻结即可正常工作。
XAML代码:
<Rectangle x:Name="viewfinderCanvas" Width="480" Height="800" Visibility="Collapsed" DoubleTap="viewfinderCanvas_DoubleTap">
<Rectangle.Fill>
<VideoBrush x:Name="videoBrush">
<VideoBrush.RelativeTransform>
<CompositeTransform x:Name="previewTransform"
CenterX=".5"
CenterY=".5" />
</VideoBrush.RelativeTransform>
</VideoBrush>
</Rectangle.Fill>
</Rectangle>
C#代码:
if ((PhotoCamera.IsCameraTypeSupported(CameraType.Primary) == true))
{
viewfinderCanvas.Visibility = Visibility.Visible;
var cam = new Microsoft.Devices.PhotoCamera(CameraType.Primary);
if (Orientation == PageOrientation.PortraitUp || Orientation ==
PageOrientation.PortraitDown || Orientation == PageOrientation.Portrait)
{
videoBrush.RelativeTransform =
new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = 90 };
}
videoBrush.SetSource(cam);
}
真的,我不知道是什么导致了VideoBrush显示的冻结。我在每个功能上都设置了断点,没有任何功能。没有错误消息......视频只是冻结。
之前有没有遇到过这个?它发生在我的设备和我编写的计算机上 - 仿真器的白框刚刚停止。
为了清楚起见 - 目的是只显示相机在应用中看到的内容 - 我没有拍照或录制视频。我只是在做这个节目。要关闭窗口,用户将双击矩形以关闭原始视图。
答案 0 :(得分:1)
我已经知道发生了什么,而且确实是我的代码。
TL:DR:具有活动VideoBrush的活动加速度计会导致VideoBrush最终冻结。
我做了什么来测试这个:
使用我的2000+代码行,我坐在那里开始评论API,引用和我通常认为会导致VideoBrush冻结的东西。每次我拿出一大块代码看我是否有所作为时,我会测试应用程序。我的测试依赖于VideoBrush冻结启动所需的秒数。
有趣的是,在删除任何内容之前,通常在VideoBrush冻结之前约45秒左右。在剪掉我的代码之后,当我突然跳到2分45秒时,我得到了我的第一个主要结果。这是在我删除了一些网格时实现的,这些网格包含一些堆叠面板,文本块和按钮,这些网格都在Blend中进行了动画处理。
在这一点上,我一直认为我的混合物不是从Visibility.Visible到Visibility.Collapsed,因此随着时间的推移积累了一些东西。事实并非如此,因为在调用VideoBrush之前崩溃所有内容的功能在2:45的冻结时间内没有变化。
我取出了所有资产,取出所有计时器,派遣计时器,秒表,日期时间实例,但它仍然没有做任何改变2:45的事情。
然后我遇到了它:我的加速度计。
为了全面了解,我在两个不同页面上的wp7应用程序中使用了加速度计。当用户第一次打开应用程序时,他将进入一个教程页面,其中有一个加速度计来模仿主页面。当完成该教程时,用户将被带到主页面,该主页面也有一个具有相同名称和事件更改通知的加速度计。
作为旁注,在查看我的代码时,我注意到我的编码错误,我没有在任何一页上实际停止/处理我的加速度计。这从未在应用程序中造成崩溃,因此它从未成为一个已实现的问题。
有了这个问题,我注意到在VideoBrush冻结之前,时间会跳到5点左右。进步,但仍然导致这种冻结?
然后我决定在启动VideoBrush之前停止加速度计,然后看看VideoBrush工作而不冻结它的图片。
很抱歉,因为如果不知道什么可以阻止VideoBrush在没有应用程序崩溃的情况下工作,这是一个不可能回答的问题。至少现在有一种已知的方法!
答案 1 :(得分:0)
正如KooKiz的评论中所述,我能够使用绝对最小代码重现VideoBrush冻结。时间可能会有所不同,但是使用下面的代码,VideoBrush可以在2分钟到14秒到2分15秒之间可靠地冻结。 (我通过运行模拟器并打开系统时钟多次计时,注意VideoBrush何时启动以及何时冻结。)
Xaml代码:
<phone:PhoneApplicationPage
x:Class="PhoneApp1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="False">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Rectangle x:Name="viewfinderCanvas" Width="480" Height="800" >
<Rectangle.Fill>
<VideoBrush x:Name="viewfinderBrush"/>
</Rectangle.Fill>
</Rectangle>
</Grid>
</phone:PhoneApplicationPage>
C#代码:
using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Devices;
using Microsoft.Devices.Sensors;
namespace PhoneApp1
{
public partial class MainPage : PhoneApplicationPage
{
private Accelerometer AccelerometerSensor;
// Constructor
public MainPage()
{
InitializeComponent();
AccelerometerSensor = new Accelerometer();
AccelerometerStartup();
if ((PhotoCamera.IsCameraTypeSupported(CameraType.Primary) == true))
{
viewfinderCanvas.Visibility = Visibility.Visible;
var cam = new Microsoft.Devices.PhotoCamera(CameraType.Primary);
viewfinderBrush.SetSource(cam);
}
}
#region Accelerometer Startup Function
private void AccelerometerStartup()
{
try
{
if (AccelerometerSensor != null)
{
AccelerometerSensor.Start();
}
}
catch (AccelerometerFailedException)
{
}
catch (UnauthorizedAccessException)
{
}
}
#endregion
}
}
答案 2 :(得分:0)
感谢您的代码,我能够重现这个问题,并找到了根本原因。
准备好了,它会成为一个&#34; ......那是什么?&#34;时刻!
基本上,整个问题就在那条线上:
var cam = new Microsoft.Devices.PhotoCamera(CameraType.Primary);
您正在创建一个新的PhotoCamera
,但您并未将该引用保留在任何位置。因此,当垃圾收集器启动时,它会处理您的孤立PhotoCamera
实例,从而冻结视频。
它很容易重现:只需在页面上添加一个按钮,然后输入点击处理程序:
GC.Collect();
只要按下按钮,视频就会冻结。
现在显而易见的问题是:为什么它只用加速度计冻结?实际上非常简单。当分配的对象总数达到阈值时,将自动触发垃圾回收。当你只有视频时,很少有对象被分配(可能没有),因此垃圾收集器不会在很长时间之前被触发。当打开加速度计时,它会以高速度更新其位置,在过程中分配新对象,因此在几分钟后触发垃圾收集。
如何解决问题?只需将PhotoCamera
引用存储在属性中:
private PhotoCamera cam;
public MainPage()
{
InitializeComponent();
AccelerometerSensor = new Accelerometer();
AccelerometerSensor.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<AccelerometerReading>>(AccelerometerSensor_CurrentValueChanged);
AccelerometerStartup();
if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary))
{
viewfinderCanvas.Visibility = Visibility.Visible;
cam = new PhotoCamera(CameraType.Primary);
viewfinderBrush.SetSource(cam);
}
}