问题描述
我正在开发 Xamarin.Forms 应用程序,出于某种原因,有多次创建的单例。然而,这并非每次都发生,而且似乎是随机的。我的依赖注入设置发生在 App.xaml.cs
using System;
using Microsoft.AppCenter;
using Microsoft.AppCenter.Analytics;
using Microsoft.AppCenter.Crashes;
using Microsoft.Extensions.DependencyInjection;
using Peripass.Mobile.Framework;
using Peripass.Mobile.Framework.DependencyInterfaces;
using Peripass.YardAssetManagementApp.Data;
using Peripass.YardAssetManagementApp.Data.FileSystem;
using Peripass.YardAssetManagementApp.Data.LocalDataServices;
using Peripass.YardAssetManagementApp.Data.Queues;
using Peripass.YardAssetManagementApp.Data.RemoteDataServices;
using Peripass.YardAssetManagementApp.Data.Syncing;
using Peripass.YardAssetManagementApp.Data.Syncing.QueueItemSyncActions;
using Peripass.YardAssetManagementApp.Device;
using Peripass.YardAssetManagementApp.MVVM;
using Peripass.YardAssetManagementApp.MVVM.Pages;
using Peripass.YardAssetManagementApp.PushNotifications;
using Peripass.YardAssetManagementApp.Services;
using Peripass.YardAssetManagementApp.StepsWizard;
using Peripass.YardAssetManagementApp.UI.Views;
using Peripass.YardAssetManagementApp.UserAuthentication;
using Peripass.YardAssetManagementApp.viewmodels;
using Xamarin.Forms;
using Application = Xamarin.Forms.Application;
namespace Peripass.YardAssetManagementApp {
public partial class App : Application,IApp {
private string _startedByAndroidNotificationMessage;
public App() {
ConfigureServices();
InitializeComponent();
AppCenter.Start($"android={Configuration.Configuration.ApplicationInsightsKeyAndroid};",typeof(Analytics),typeof(Crashes));
MainPage = ServiceProvider.GetrequiredService<MainPage>();
}
public static IServiceCollection Services { get; } = new ServiceCollection();
public IServiceProvider ServiceProvider { get; set; }
private void ConfigureServices() {
Services.AddSingleton<ILifecycleHooksService,LifecycleHooksService>();
Services.AddTransient<InetworkinformationProvider,networkinformationProvider>();
RegisterLocalDataServices();
RegisterRemoteDataServices();
RegisterSyncLogic();
RegisterServices();
RegisterViews();
Services.AddSingleton<IUserManager,UserManager>();
Services.AddSingleton<HttpClientProvider>();
Services.AddSingleton<ILogger,Logger>();
Services.AddSingleton<INavigationService,NavigationService>();
Services.AddSingleton<StepsWizardManager>();
Services.AddSingleton<MainPage>();
Services.AddSingleton(DependencyService.Get<ILocalFileSystem>());
Services.AddSingleton<IRestServiceHelper,RestServiceHelper>();
Services.AddSingleton<IPushNotificationsService,PushNotificationsService>();
ServiceProvider = Services.BuildServiceProvider();
}
public void RegisterServices() {
Services.AddTransient<ITaskService,TaskService>();
Services.AddTransient<ILocationService,LocationService>();
Services.AddTransient<ILocalizationService,LocalizationService>();
Services.AddTransient<IDiagnosticsService,DiagnosticsService>();
}
public void RegisterLocalDataServices() {
Services.AddSingleton<ILocalTaskDataService,LocalTaskDataService>();
Services.AddSingleton<ILocalLocationDataService,LocalLocationDataService>();
Services.AddSingleton<ILocalUserDataService,LocalUserDataService>();
Services.AddSingleton<ILocalPushNotificationDataService,LocalPushNotificationDataService>();
Services.AddSingleton<ILocalPictureDataService,LocalPictureDataService>();
Services.AddSingleton<ISafeFileSystem,SafeFileSystem>();
Services.AddSingleton<ILocalLocalizationDataService,LocalLocalizationDataService>();
}
public void RegisterRemoteDataServices() {
Services.AddSingleton<IRemoteTaskDataService,RemoteTaskDataService>();
Services.AddSingleton<IRemoteLocationDataService,RemoteLocationDataService>();
Services.AddSingleton<IRemoteUserDataService,RemoteUserDataService>();
Services.AddSingleton<IRemoteFileDataService,RemoteFileDataService>();
Services.AddSingleton<IRemoteLocalizationDataService,RemoteLocalizationDataService>();
}
public void RegisterSyncLogic() {
Services.AddSingleton<IToMobileTasksSyncer,ToMobileTasksSyncer>();
Services.AddSingleton<IQueue,IncomingHighPriorityQueue>();
Services.AddSingleton<IQueue,IncomingLowPriorityQueue>();
Services.AddSingleton<IQueue,OutgoingHighPriorityQueue>();
Services.AddSingleton<IQueue,OutgoingLowPriorityQueue>();
Services.AddSingleton<IQueue,PictureSyncLowPriorityQueue>();
Services.AddSingleton<IQueue,PictureSyncHighPriorityQueue>();
Services.AddSingleton<IQueueorchestrator,IncomingQueueorchestrator>();
Services.AddSingleton<IQueueorchestrator,OutgoingQueueorchestrator>();
Services.AddSingleton<IQueueorchestrator,PictureQueueorchestrator>();
Services.AddSingleton<IQueueProcessor,IncomingQueueProcessor>();
Services.AddSingleton<IQueueProcessor,OutgoingQueueProcessor>();
Services.AddSingleton<IQueueProcessor,PictureQueueProcessor>();
Services.AddSingleton<IQueueItemSyncAction,FetchTaskDetailSyncAction>();
Services.AddSingleton<IQueueItemSyncAction,OutgoingStepValueUpdateSyncAction>();
Services.AddSingleton<IQueueItemSyncAction,OutgoingTaskStatusChangedSyncAction>();
Services.AddSingleton<IQueueItemSyncAction,SyncPictureAction>();
Services.AddSingleton<IFileIntegrityHelper,FileIntegrityHelper>();
}
public void RegisterViews() {
Services.AddTransient<LoginViewContent>();
Services.AddSingleton<Loginviewmodel>();
Services.AddTransient<UserInfoViewContent>();
Services.AddSingleton<UserInfoviewmodel>();
Services.AddTransient<MainTaskListViewContent>();
Services.AddSingleton<MainTaskListviewmodel>();
Services.AddTransient<TaskDetailViewContent>();
Services.AddSingleton<TaskDetailviewmodel>();
Services.AddTransient<IntegerFieldTaskStepViewContent>();
Services.AddSingleton<IntegerFieldTaskStepviewmodel>();
Services.AddTransient<TextAreaTaskStepViewContent>();
Services.AddSingleton<TextAreaTaskStepviewmodel>();
Services.AddTransient<DropDownTaskStepViewContent>();
Services.AddSingleton<DropDownTaskStepviewmodel>();
Services.AddTransient<MovetoLocationSummaryViewContent>();
Services.AddSingleton<MovetoLocationSummaryviewmodel>();
Services.AddTransient<TakePictureStepViewContent>();
Services.AddSingleton<TakePictureStepviewmodel>();
Services.AddTransient<MovetoLocationStepViewContent>();
Services.AddSingleton<MovetoLocationStepviewmodel>();
Services.AddTransient<TaskCompletedViewContent>();
Services.AddSingleton<TaskCompletedviewmodel>();
Services.AddTransient<LoggedOutViewContent>();
Services.AddSingleton<LoggedOutviewmodel>();
Services.AddTransient<TextFieldTaskStepViewContent>();
Services.AddSingleton<TextFieldTaskStepviewmodel>();
Services.AddTransient<DecimalFieldTaskStepViewContent>();
Services.AddSingleton<DecimalFieldTaskStepviewmodel>();
Services.AddTransient<GenericExceptionPageViewContent>();
Services.AddSingleton<GenericExceptionPageviewmodel>();
Services.AddTransient<CleanupBeforelogoutPageViewContent>();
Services.AddSingleton<CleanupBeforelogoutPageviewmodel>();
Services.AddTransient<SelectLanguageViewContent>();
Services.AddSingleton<SelectLanguageviewmodel>();
}
protected override async void OnStart() {
await ServiceProvider.GetrequiredService<ILifecycleHooksService>().OnStart();
}
protected override void OnSleep() { }
protected override async void OnResume() {
await ServiceProvider.GetrequiredService<ILifecycleHooksService>().OnResume();
}
public void StartedByTapOnAndroidNotification(string message) {
_startedByAndroidNotificationMessage = message;
}
}
}
多次创建的单例就是这些。可能其他单身人士也被创建了多次,但我敢肯定。
Services.AddSingleton<IQueueorchestrator,PictureQueueProcessor>();
我发现在解析 ILifecycleHooksService 的依赖项时,有时会多次调用 OnStart 方法,创建这些单例的多个实例。这是 LifeCycleHooksService 中的代码:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Peripass.YardAssetManagementApp.Data;
using Peripass.YardAssetManagementApp.Data.LocalDataServices;
using Peripass.YardAssetManagementApp.Data.Syncing;
using Peripass.YardAssetManagementApp.MVVM;
using Peripass.YardAssetManagementApp.PushNotifications;
using Peripass.YardAssetManagementApp.viewmodels;
namespace Peripass.YardAssetManagementApp {
public interface ILifecycleHooksService {
Task OnStart();
Task OnResume();
}
public class LifecycleHooksService : ILifecycleHooksService {
private readonly INavigationService _navigationService;
private readonly ILocalUserDataService _localUserDataService;
private readonly ILocalTaskDataService _localTaskDataService;
private readonly ILocalLocationDataService _localLocationDataService;
private readonly ILocalPushNotificationDataService _localPushNotificationDataService;
private readonly ILocalPictureDataService _localPictureDataService;
private readonly IToMobileTasksSyncer _toMobileTasksSyncer;
private readonly IEnumerable<IQueueProcessor> _queueProcessors;
private readonly IPushNotificationsService _pushNotificationsService;
private readonly ILocalLocalizationDataService _localLocalizationDataService;
public LifecycleHooksService(INavigationService navigationService,ILocalUserDataService localUserDataService,IToMobileTasksSyncer toMobileTasksSyncer,IEnumerable<IQueueProcessor> queueProcessors,ILocalTaskDataService localTaskDataService,ILocalLocationDataService localLocationDataService,ILocalPushNotificationDataService localPushNotificationDataService,IPushNotificationsService pushNotificationsService,ILocalPictureDataService localPictureDataService,ILocalLocalizationDataService localLocalizationDataService) {
_navigationService = navigationService;
_localUserDataService = localUserDataService;
_toMobileTasksSyncer = toMobileTasksSyncer;
_queueProcessors = queueProcessors;
_localTaskDataService = localTaskDataService;
_localLocationDataService = localLocationDataService;
_localPushNotificationDataService = localPushNotificationDataService;
_pushNotificationsService = pushNotificationsService;
_localPictureDataService = localPictureDataService;
_localLocalizationDataService = localLocalizationDataService;
}
public async Task OnStart() {
await ReloadData();
await CreatedeviceidOnFirstStartAsync();
var currentUser = _localUserDataService.GetCurrentUser();
if (currentUser.IsLoggedIn) {
Configuration.Configuration.SetEnvironment(currentUser.Environment);
await _navigationService.NavigatetoviewmodelAsync<MainTaskListviewmodel>(true);
try {
await _toMobileTasksSyncer.SyncAllMetaData();
}
catch {
// ignored
}
}
else {
await _navigationService.NavigatetoviewmodelAsync<Loginviewmodel>();
}
foreach (var queueProcessor in _queueProcessors) {
_ = Task.Run(async () => await queueProcessor.StartPeriodicProcessing());
}
}
public async Task OnResume() {
try {
await _toMobileTasksSyncer.SyncAllTasks(true);
}
catch {
// ignored
}
}
public async Task CreatedeviceidOnFirstStartAsync() {
var currentPushNotificationInfo = await _localPushNotificationDataService.GetCurrentPushNotificationInfo();
if (string.IsNullOrEmpty(currentPushNotificationInfo.deviceidTag)) {
await _localPushNotificationDataService.Setdeviceid(Guid.NewGuid().ToString());
}
}
private async Task ReloadData() {
await _localLocalizationDataService.ReloadData();
await _localUserDataService.ReloadData();
await _localTaskDataService.ReloadData();
await _localLocationDataService.ReloadData();
await _localPictureDataService.ReloadData();
await _pushNotificationsService.ProcessReceivedMessages();
}
}
}
在这个类中,我注入了 IQueueProcessors 的 I Enumerable。这些 queueProcessor 为自己注入了 IQueueorchestrators。如果您需要更多信息,请随时问我。
解决方法
我找到了导致它的原因。原因与 android 相关,并在此堆栈溢出帖子中进行了描述:description of what causes this
对我有用的解决方案来自这篇关于同一主题的帖子:solution for me
基本上对我有用的解决方案是将它添加到 OnCreate 中:
// Possible work around for market launches. See https://issuetracker.google.com/issues/36907463
// for more details. Essentially,the market launches the main activity on top of other activities.
// we never want this to happen. Instead,we check if we are the root and if not,we finish.
if (!isTaskRoot()) {
final Intent intent = getIntent();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && Intent.ACTION_MAIN.equals(intent.getAction())) {
Log.w(LOG_TAG,"Main Activity is not the root. Finishing Main Activity instead of launching.");
finish();
return;
}
}