当应用程序暂停时,Windows UWP对我的Lazy初始化Singleton类做了什么?

时间:2017-07-26 19:49:05

标签: c# .net windows-10-universal windows-10-mobile

我有一个在Windows 10 Mobile上运行的UWP应用程序,用c#编写。我的一个类需要是一个Singleton而且我使用Lazy模式进行初始化时遇到问题。我是这样做的(这几乎是每个人都这样做的)

public class WindowsUniversalScanners
{
    private static readonly Lazy<WindowsUniversalScanners> lWindowsScanner = new Lazy<WindowsUniversalScanners>(() => new WindowsUniversalScanners());

    public static WindowsUniversalScanners Instance { get { return lWindowsScanner.Value; } }

    public delegate void ScannerDataEventHandler(ScannerDataEventArgs se);

    public event ScannerDataEventHandler onScanData;

    public delegate void ScannerStatusEventHandler(ScannerStatusEventArgs se);

    public event ScannerStatusEventHandler onScanStatus;

    public delegate void ScannerInitializationStatus(ScannerInitEventArgs si);

    public event ScannerInitializationStatus onScannerInit;

    private WindowsUniversalScanners()
    {
        StartScanner();
    }

当应用程序从头开始并“正常”使用时,一切正常。但是,如果应用程序被暂停(意味着您切换到另一个应用程序,点击Windows键等等)然后恢复,则此类中的事件不会再提高。

我还可以在此类的代码中放置断点,并看到断点在挂起之前应该被击中,但在挂起之后,断点不再出现(这最终导致事件永远不会触发)。

所以,我假设Windows在应用程序暂停时销毁了我的Singleton?注意,这也不是时间问题。我读到当应用程序暂停x秒并且操作系统需要释放资源时它可以终止事情。但是,即使我暂停了一秒钟又回来,这个问题也会发生。应用程序的大多数其他功能在恢复后仍能正常工作。

那么,当应用程序被专门暂停时,有人可以确认操作系统对单身人士做了什么吗?我已经在应用程序生命周期的MSDN文档上做了大量阅读,但没有解决这个特定问题。

另外,确认实际上这个类为null的最佳方法是什么?我可以检查Instance = null是否可以验证?假设它是,我想我只需要重新实例化它?

谢谢!

1 个答案:

答案 0 :(得分:1)

事实证明,这个班级并没有被处理掉。我相信如果不再提及课程,可能会在5到10秒后由GC处理掉。这将满足操作系统在暂停时处理此类的标准,以减少暂停的应用程序的占用空间。但是,这不是我的情况,因为它是一个Singleton,我仍然从我的页面中获取它的引用。

请注意!!!就我而言,硬件是PointOfService命名空间中的条形码扫描器。但是,Windows.Devices或其他命名空间中的任何硬件项都可能发生此问题。像NFC,GPS等等。你应该在从暂停状态恢复后警惕并检查以下解决方案的应用程序:

因此,操作系统将会清理其他事情&#34;暂停时是任何硬件资源。就我而言,我有一个使用命名空间的条形码扫描器:

using Windows.Devices.PointOfService;

然后您必须&#34;声明&#34;扫描仪做这样的事情:

BarcodeScanner.ClaimScannerAsync();

但是,据我所知,操作系统可以随时将声明部署到您的设备上。还有一点需要注意。如果你在课堂上做类似的事情或像我这样做的话:

private BarcodeScanner scanner = null;
public ClaimedBarcodeScanner ClaimedScanner { get; set; } = null;

然后在您的构造函数或其他初始化方法中,使用BarcodeScanner和ClaimedBarcodeScanner对象填充这些属性,然后操作系统将连接部署到硬件,您将失去&#34;声明&#34;对他们来说,你的对象不会再次为null,但如果你试图访问或使用它们,你将得到一个ObjectDisposedException。这是关键,因为当您尝试在任何时候重新连接时,尤其是在简历之后,您不能只测试这些属性是否为空,因为它们不会。相反,您必须尝试在try / catch块中使用它们并捕获ObjectDisposedException,此时,重新连接或回收您的硬件(或我的情况下的扫描仪)。

所以,我做的是获取App Resuming事件然后在那个事件中,尝试使用该对象,如果我捕获异常,使用它重新连接如下:

private WindowsUniversalScanners()
{
    //Get our event for when the app resumes from suspended state
    Application.Current.Resuming += App_Resuming;
    StartScanner();
}

private async void App_Resuming(object sender, object e)
{
    try
    {
        //When the app resumes from suspended state, the ClaimedScanner object will be disposed but NOT null. This means the only 
        //way to trap this is try to access a property in the object and catch an ObjectDisposedException. 
        var scannerStatus = ClaimedScanner.IsEnabled;
    }
    catch (ObjectDisposedException oe)
    {
        //Now we know we are in a stuck state, we can try to heal from it. First we destroy scanner object and set it to null.
        if (DestroyScanner())
        {
            //Finally we re-start the scanner
            await StartScanner();
        }
    }
}

希望这有帮助!