public AutoSuspendAppDelegate() { var host = new SuspensionHost(); host.IsLaunchingNew = Observable.Never <Unit>(); host.IsResuming = _finishedLaunching.Select(_ => Unit.Default); host.IsUnpausing = _activated.Select(_ => Unit.Default); var untimelyDeath = new Subject <Unit>(); AppDomain.CurrentDomain.UnhandledException += (o, e) => untimelyDeath.OnNext(Unit.Default); host.ShouldInvalidateState = untimelyDeath; host.ShouldPersistState = _willTerminate.Merge(_backgrounded).SelectMany(app => { var taskId = app.BeginBackgroundTask(new NSAction(() => untimelyDeath.OnNext(Unit.Default))); // NB: We're being force-killed, signal invalidate instead if (taskId == UIApplication.BackgroundTaskInvalid) { untimelyDeath.OnNext(Unit.Default); return(Observable.Empty <IDisposable>()); } return(Observable.Return( Disposable.Create(() => app.EndBackgroundTask(taskId)))); }); SuspensionHost = host; }
protected AutoSuspendApplication() { var host = new SuspensionHost(); var launchNew = new[] { ApplicationExecutionState.ClosedByUser, ApplicationExecutionState.NotRunning, }; host.IsLaunchingNew = _launched .Where(x => launchNew.Contains(x.PreviousExecutionState)) .Select(_ => Unit.Default); host.IsResuming = _launched .Where(x => x.PreviousExecutionState == ApplicationExecutionState.Terminated) .Select(_ => Unit.Default); var unpausing = new[] { ApplicationExecutionState.Suspended, ApplicationExecutionState.Running, }; host.IsUnpausing = _launched .Where(x => unpausing.Contains(x.PreviousExecutionState)) .Select(_ => Unit.Default); var shouldPersistState = new Subject<SuspendingEventArgs>(); Suspending += (o, e) => shouldPersistState.OnNext(e); host.ShouldPersistState = shouldPersistState.Select(x => { var deferral = x.SuspendingOperation.GetDeferral(); return Disposable.Create(deferral.Complete); }); var shouldInvalidateState = new Subject<Unit>(); UnhandledException += (o, e) => shouldInvalidateState.OnNext(Unit.Default); host.ShouldInvalidateState = shouldInvalidateState; SuspensionHost = host; }
public AutoSuspendAppDelegate() { var host = new SuspensionHost(); host.IsLaunchingNew = Observable.Never<Unit>(); host.IsResuming = _finishedLaunching.Select(_ => Unit.Default); host.IsUnpausing = _activated.Select(_ => Unit.Default); var untimelyDeath = new Subject<Unit>(); AppDomain.CurrentDomain.UnhandledException += (o,e) => untimelyDeath.OnNext(Unit.Default); host.ShouldInvalidateState = untimelyDeath; host.ShouldPersistState = _willTerminate.Merge(_backgrounded).SelectMany(app => { var taskId = app.BeginBackgroundTask(new NSAction(() => untimelyDeath.OnNext(Unit.Default))); // NB: We're being force-killed, signal invalidate instead if (taskId == UIApplication.BackgroundTaskInvalid) { untimelyDeath.OnNext(Unit.Default); return Observable.Empty<IDisposable>(); } return Observable.Return( Disposable.Create(() => app.EndBackgroundTask(taskId))); }); SuspensionHost = host; }
public AutoSuspendActivityHelper(Activity hostActivity) { var methodsToCheck = new[] { "OnCreate", "OnResume", "OnPause", "OnSaveInstanceState", }; var missingMethod = methodsToCheck .Select(x => { var methods = hostActivity.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); return(Tuple.Create(x, methods.FirstOrDefault(y => y.Name == x))); }) .FirstOrDefault(x => x.Item2 == null); if (missingMethod != null) { throw new Exception(String.Format("Your activity must implement {0} and call AutoSuspendActivityHelper.{0}", missingMethod.Item1)); } Observable.Merge(onCreate, onSaveInstanceState) .Subscribe(x => AndroidSuspensionHost.latestBundle = x); var host = new SuspensionHost(); host.IsLaunchingNew = onCreate.Select(_ => Unit.Default); host.IsResuming = onResume; host.IsUnpausing = onResume; bool hasRecentlyCrashed = false; host.SetupDefaultSuspendResumeFunc = new Action <ISuspensionDriver>(driver => { driver = driver ?? RxApp.DependencyResolver.GetService <ISuspensionDriver>(); // TODO: Handle crashes here host.ShouldInvalidateState .SelectMany(_ => driver.InvalidateState()) .LoggedCatch(this, Observable.Return(Unit.Default), "Tried to invalidate app state") .Subscribe(_ => this.Log().Info("Invalidated app state")); host.ShouldPersistState .SelectMany(x => driver.SaveState(RootState.Current.ViewModel).Finally(x.Dispose)) .LoggedCatch(this, Observable.Return(Unit.Default), "Tried to persist app state") .Subscribe(_ => this.Log().Info("Persisted application state")); host.IsResuming .SelectMany(x => driver.LoadState <IApplicationRootState>()) .LoggedCatch(this, Observable.Defer(() => Observable.Return(RxApp.DependencyResolver.GetService <IApplicationRootState>())), "Failed to restore app state from storage, creating from scratch") .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => RootState.Current.ViewModel = x); host.IsLaunchingNew.Subscribe(_ => { RootState.Current.ViewModel = RxApp.DependencyResolver.GetService <IApplicationRootState>(); }); }); SuspensionHost = host; AndroidSuspensionHost.inner = host; }
protected AutoSuspendApplication() { var host = new SuspensionHost(); host.IsLaunchingNew = Observable.FromEventPattern<LaunchingEventArgs>( x => PhoneApplicationService.Current.Launching += x, x => PhoneApplicationService.Current.Launching -= x) .Select(_ => Unit.Default); host.IsUnpausing = Observable.FromEventPattern<ActivatedEventArgs>( x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x) .Where(x => x.EventArgs.IsApplicationInstancePreserved) .Select(_ => Unit.Default); // NB: "Applications should not perform resource-intensive tasks // such as loading from isolated storage or a network resource // during the Activated event handler because it increase the time // it takes for the application to resume" host.IsResuming = Observable.FromEventPattern<ActivatedEventArgs>( x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x) .Where(x => !x.EventArgs.IsApplicationInstancePreserved) .Select(_ => Unit.Default) .ObserveOn(RxApp.TaskpoolScheduler); // NB: No way to tell OS that we need time to suspend, we have to // do it in-process host.ShouldPersistState = Observable.Merge( Observable.FromEventPattern<DeactivatedEventArgs>( x => PhoneApplicationService.Current.Deactivated += x, x => PhoneApplicationService.Current.Deactivated -= x) .Select(_ => Disposable.Empty), Observable.FromEventPattern<ClosingEventArgs>( x => PhoneApplicationService.Current.Closing += x, x => PhoneApplicationService.Current.Closing -= x) .Select(_ => Disposable.Empty)); host.ShouldInvalidateState = Observable.FromEventPattern<ApplicationUnhandledExceptionEventArgs>(x => UnhandledException += x, x => UnhandledException -= x) .Select(_ => Unit.Default); SuspensionHost = host; }
protected AutoSuspendApplication() { var host = new SuspensionHost(); var launchNew = new[] { ApplicationExecutionState.ClosedByUser, ApplicationExecutionState.NotRunning, }; host.IsLaunchingNew = _launched .Where(x => launchNew.Contains(x.PreviousExecutionState)) .Select(_ => Unit.Default); host.IsResuming = _launched .Where(x => x.PreviousExecutionState == ApplicationExecutionState.Terminated) .Select(_ => Unit.Default); var unpausing = new[] { ApplicationExecutionState.Suspended, ApplicationExecutionState.Running, }; host.IsUnpausing = _launched .Where(x => unpausing.Contains(x.PreviousExecutionState)) .Select(_ => Unit.Default); var shouldPersistState = new Subject <SuspendingEventArgs>(); Suspending += (o, e) => shouldPersistState.OnNext(e); host.ShouldPersistState = shouldPersistState.Select(x => { var deferral = x.SuspendingOperation.GetDeferral(); return(Disposable.Create(deferral.Complete)); }); var shouldInvalidateState = new Subject <Unit>(); UnhandledException += (o, e) => shouldInvalidateState.OnNext(Unit.Default); host.ShouldInvalidateState = shouldInvalidateState; SuspensionHost = host; }
protected AutoSuspendApplication() { var host = new SuspensionHost(); host.IsLaunchingNew = Observable.FromEventPattern <LaunchingEventArgs>( x => PhoneApplicationService.Current.Launching += x, x => PhoneApplicationService.Current.Launching -= x) .Select(_ => Unit.Default); host.IsUnpausing = Observable.FromEventPattern <ActivatedEventArgs>( x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x) .Where(x => x.EventArgs.IsApplicationInstancePreserved) .Select(_ => Unit.Default); // NB: "Applications should not perform resource-intensive tasks // such as loading from isolated storage or a network resource // during the Activated event handler because it increase the time // it takes for the application to resume" host.IsResuming = Observable.FromEventPattern <ActivatedEventArgs>( x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x) .Where(x => !x.EventArgs.IsApplicationInstancePreserved) .Select(_ => Unit.Default) .ObserveOn(RxApp.TaskpoolScheduler); // NB: No way to tell OS that we need time to suspend, we have to // do it in-process host.ShouldPersistState = Observable.Merge( Observable.FromEventPattern <DeactivatedEventArgs>( x => PhoneApplicationService.Current.Deactivated += x, x => PhoneApplicationService.Current.Deactivated -= x) .Select(_ => Disposable.Empty), Observable.FromEventPattern <ClosingEventArgs>( x => PhoneApplicationService.Current.Closing += x, x => PhoneApplicationService.Current.Closing -= x) .Select(_ => Disposable.Empty)); host.ShouldInvalidateState = Observable.FromEventPattern <ApplicationUnhandledExceptionEventArgs>(x => UnhandledException += x, x => UnhandledException -= x) .Select(_ => Unit.Default); SuspensionHost = host; // // Do the equivalent steps that the boilerplate code does for WP8 apps // if (RootFrame != null) { return; } RootFrame = new PhoneApplicationFrame(); var currentBackHook = default(IDisposable); var currentViewFor = default(WeakReference <IViewFor>); RootFrame.Navigated += (o, e) => { // Always clear the WP8 Back Stack, we're using our own while (RootFrame.RemoveBackEntry() != null) { } if (currentBackHook != null) { currentBackHook.Dispose(); } var page = RootFrame.Content as PhoneApplicationPage; if (page != null) { currentBackHook = Observable.FromEventPattern <CancelEventArgs>(x => page.BackKeyPress += x, x => page.BackKeyPress -= x) .Where(_ => ViewModel != null) .Subscribe(x => { if (!ViewModel.Router.NavigateBack.CanExecute(null)) { return; } x.EventArgs.Cancel = true; ViewModel.Router.NavigateBack.Execute(null); }); var viewFor = page as IViewFor; if (viewFor == null) { throw new Exception("Your Main Page (i.e. the one that is pointed to by WMAppManifest) must implement IViewFor<YourAppBootstrapperClass>"); } currentViewFor = new WeakReference <IViewFor>(viewFor); viewFor.ViewModel = ViewModel; } // Finally make it live RootVisual = RootFrame; }; _viewModelChanged.StartWith(ViewModel).Where(x => x != null).Subscribe(vm => { var viewFor = default(IViewFor); if (currentViewFor != null && currentViewFor.TryGetTarget(out viewFor)) { viewFor.ViewModel = vm; } }); UnhandledException += (o, e) => { if (Debugger.IsAttached) { Debugger.Break(); } }; RootFrame.NavigationFailed += (o, e) => { if (Debugger.IsAttached) { Debugger.Break(); } }; }
protected AutoSuspendApplication() { var host = new SuspensionHost(); host.IsLaunchingNew = Observable.FromEventPattern<LaunchingEventArgs>( x => PhoneApplicationService.Current.Launching += x, x => PhoneApplicationService.Current.Launching -= x) .Select(_ => Unit.Default); host.IsUnpausing = Observable.FromEventPattern<ActivatedEventArgs>( x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x) .Where(x => x.EventArgs.IsApplicationInstancePreserved) .Select(_ => Unit.Default); // NB: "Applications should not perform resource-intensive tasks // such as loading from isolated storage or a network resource // during the Activated event handler because it increase the time // it takes for the application to resume" host.IsResuming = Observable.FromEventPattern<ActivatedEventArgs>( x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x) .Where(x => !x.EventArgs.IsApplicationInstancePreserved) .Select(_ => Unit.Default) .ObserveOn(RxApp.TaskpoolScheduler); // NB: No way to tell OS that we need time to suspend, we have to // do it in-process host.ShouldPersistState = Observable.Merge( Observable.FromEventPattern<DeactivatedEventArgs>( x => PhoneApplicationService.Current.Deactivated += x, x => PhoneApplicationService.Current.Deactivated -= x) .Select(_ => Disposable.Empty), Observable.FromEventPattern<ClosingEventArgs>( x => PhoneApplicationService.Current.Closing += x, x => PhoneApplicationService.Current.Closing -= x) .Select(_ => Disposable.Empty)); host.ShouldInvalidateState = Observable.FromEventPattern<ApplicationUnhandledExceptionEventArgs>(x => UnhandledException += x, x => UnhandledException -= x) .Select(_ => Unit.Default); SuspensionHost = host; // // Do the equivalent steps that the boilerplate code does for WP8 apps // if (RootFrame != null) return; RootFrame = new PhoneApplicationFrame(); var currentBackHook = default(IDisposable); var currentViewFor = default(WeakReference<IViewFor>); RootFrame.Navigated += (o, e) => { // Always clear the WP8 Back Stack, we're using our own while (RootFrame.RemoveBackEntry() != null) {} if (currentBackHook != null) currentBackHook.Dispose(); var page = RootFrame.Content as PhoneApplicationPage; if (page != null) { currentBackHook = Observable.FromEventPattern<CancelEventArgs>(x => page.BackKeyPress += x, x => page.BackKeyPress -= x) .Where(_ => ViewModel != null) .Subscribe(x => { if (!ViewModel.Router.NavigateBack.CanExecute(null)) return; x.EventArgs.Cancel = true; ViewModel.Router.NavigateBack.Execute(null); }); var viewFor = page as IViewFor; if (viewFor == null) { throw new Exception("Your Main Page (i.e. the one that is pointed to by WMAppManifest) must implement IViewFor<YourAppBootstrapperClass>"); } currentViewFor = new WeakReference<IViewFor>(viewFor); viewFor.ViewModel = ViewModel; } // Finally make it live RootVisual = RootFrame; }; _viewModelChanged.StartWith(ViewModel).Where(x => x != null).Subscribe(vm => { var viewFor = default(IViewFor); if (currentViewFor != null && currentViewFor.TryGetTarget(out viewFor)) { viewFor.ViewModel = vm; } }); UnhandledException += (o, e) => { if (Debugger.IsAttached) Debugger.Break(); }; RootFrame.NavigationFailed += (o, e) => { if (Debugger.IsAttached) Debugger.Break(); }; }
static AndroidSuspensionHost() { inner = new SuspensionHost(); }