Xamarin应用程序进入后台后,Lazy初始化的singleton会发生什么



我在Xamarin中为应用程序singleton使用Lazy初始化。Forms(应用程序在iOS上运行(:

public sealed class DataSingleton
{
private static readonly Lazy<DataSingleton> lazy = new Lazy<DataSingleton>(() => new DataSingleton(), LazyThreadSafetyMode.PublicationOnly); // tried withou 2nd parameter as well
public static DataSingleton Instance
{
get { return lazy.Value; }
}
...
}

我在运行为前端提供数据的web服务器中称之为Angular(使用web视图显示Angular代码(

var server = new WebServer(o => o
.WithUrlPrefix($"http://localhost:{appSettings.ApiPort}")
.WithMode(HttpListenerMode.EmbedIO))
.WithCors()
.WithLocalSessionManager()
.WithWebApi("/api", m => m
.WithController<TestController>()
.WithController<SettingsController>()
.WithController<ReportController>()
.WithController<SystemController>())
.WithModule(new ActionModule("/", HttpVerbs.Any,
ctx => ctx.SendDataAsync(new { Message = "Error" })))
.RunAsync();

在控制器中,调用DataSingleton来获取/设置数据,但在应用程序从后台返回后,DataSingleton.Instance为null。

当应用程序在后台短时间(大约5分钟(时,我应该怎么做才能不丢失singleton的数据

更新-我发现这个问题只出现在控制器中,因为当应用程序回到前台时,我可以在AppDelegateWillEnterForeground事件中看到所有数据。。

如果是Web服务器出现问题,请在应用程序进入后台时停止它。当应用程序返回时再次启动(或根据需要延迟启动(。

代码可能是这样的:

App.xaml.cs:

public static Webserver MyWebServer
{
get
{
if (_server == null)
{
_server = new Webserver(...);
}
return _server;
}
}
public static void StopWebServer()
{
if (_server != null)
{
_server.Dispose();
// So will be created again, on next reference to MyWebServer.
_server = null;
}
}
private static Webserver _server;
...
protected override void OnSleep()
{
StopWebServer();
}

其他用途:

... App.MyWebServer ...

如果你不想让静态变量(尽管IMHO对应用程序来说是可以的,因为只有一个,它的寿命是应用程序本身的寿命(,那么删除";静态";s以上,其他地方的用法变为:

... (Xamarin.Forms.Application.Current as App).MyWebServer ...

在这种情况下,可能存在竞争条件。如果两个(或多个线程(第一次同时读取Instance,则会创建多个DataSingleton实例。然而,每隔一次读取将只获得一个实例。这取决于你的场景,如果可以的话。

public sealed class DataSingleton {
private static instance;
// will assign new DataSingleton only if "instance" is null.
public static Instance => instance ??= new DataSingleton();
}

或者,您可以使用Interlocked类来确保,如果另一个线程已经初始化了instance字段,则instance字段不会被覆盖。

public sealed class DataSingleton {
private static instance;
public static Instance {
get {
var result = instance;
// early exit if singleton is already initialized
if (result is not null) return result;
var created = new DataSingleton();
// thread-safe way how to assign "created" into "instance" only if "instance" refers to null. othervise no assignment will be made
var original = Interlocked.CompareExchange(ref instance, null, created);
// some other thread already initialized singleton
if (original is not null) return original;
// return newly created instance
return result;
}
}
}

或者,您可以使用lock来确保只创建一个实例。

public sealed class DataSingleton {
private static instance;
public static Instance {
get {
var result = instance;
// early exit if singleton is already initialized
if (result is not null) return result;
lock(typeof(DataSingleton)) {
result = instance;
// double check, if instance was not initialized by another thread
if (result is not null) return result;

return instance = new DataSingleton();
}
}
}
}

最新更新