/// <summary> /// Setup our suspension driver for a class derived off ISuspensionHost interface. /// This will make your suspension host respond to suspend and resume requests. /// </summary> /// <param name="item">The suspension host.</param> /// <param name="driver">The suspension driver.</param> /// <returns>A disposable which will stop responding to Suspend and Resume requests.</returns> public static IDisposable SetupDefaultSuspendResume(this ISuspensionHost item, ISuspensionDriver?driver = null) { if (item is null) { throw new ArgumentNullException(nameof(item)); } var ret = new CompositeDisposable(); driver ??= Locator.Current.GetService <ISuspensionDriver>(); ret.Add(item.ShouldInvalidateState .SelectMany(_ => driver.InvalidateState()) .LoggedCatch(item, Observables.Unit, "Tried to invalidate app state") .Subscribe(_ => item.Log().Info("Invalidated app state"))); ret.Add(item.ShouldPersistState .SelectMany(x => driver.SaveState(item.AppState !).Finally(x.Dispose)) .LoggedCatch(item, Observables.Unit, "Tried to persist app state") .Subscribe(_ => item.Log().Info("Persisted application state"))); ret.Add(item.IsResuming.Merge(item.IsLaunchingNew) .SelectMany(_ => driver.LoadState()) .LoggedCatch( item, Observable.Defer(() => Observable.Return(item.CreateNewAppState?.Invoke())), "Failed to restore app state from storage, creating from scratch") .Subscribe(x => item.AppState = x ?? item.CreateNewAppState?.Invoke())); return(ret); }
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; }
/// <summary> /// /// </summary> /// <param name="This"></param> /// <param name="driver"></param> /// <returns></returns> public static IDisposable SetupDefaultSuspendResume(this ISuspensionHost This, ISuspensionDriver driver = null) { var ret = new CompositeDisposable(); driver = driver ?? Locator.Current.GetService <ISuspensionDriver>(); ret.Add(This.ShouldInvalidateState .SelectMany(_ => driver.InvalidateState()) .LoggedCatch(This, Observables.Unit, "Tried to invalidate app state") .Subscribe(_ => This.Log().Info("Invalidated app state"))); ret.Add(This.ShouldPersistState .SelectMany(x => driver.SaveState(This.AppState).Finally(x.Dispose)) .LoggedCatch(This, Observables.Unit, "Tried to persist app state") .Subscribe(_ => This.Log().Info("Persisted application state"))); ret.Add(Observable.Merge(This.IsResuming, This.IsLaunchingNew) .SelectMany(x => driver.LoadState()) .LoggedCatch(This, Observable.Defer(() => Observable.Return(This.CreateNewAppState())), "Failed to restore app state from storage, creating from scratch") .Subscribe(x => This.AppState = x ?? This.CreateNewAppState())); return(ret); }
/// <summary> /// Observe changes to the AppState of a class derived from ISuspensionHost. /// </summary> /// <typeparam name="T">The observable type.</typeparam> /// <param name="item">The suspension host.</param> /// <returns>An observable of the app state.</returns> public static IObservable <T> ObserveAppState <T>(this ISuspensionHost item) where T : class { return(item.WhenAny(suspensionHost => suspensionHost.AppState, observedChange => observedChange.Value) .Where(x => x != null) .Cast <T>()); }
/// <summary> /// Get the current App State of a class derived from ISuspensionHost. /// </summary> /// <typeparam name="T">The app state type.</typeparam> /// <param name="item">The suspension host.</param> /// <returns>The app state.</returns> public static T GetAppState <T>(this ISuspensionHost item) { if (item is null) { throw new ArgumentNullException(nameof(item)); } return((T)item.AppState !); }
/// <summary> /// Initializes static members of the <see cref="RxApp"/> class. /// </summary> /// <exception cref="UnhandledErrorException">Default exception when we have unhandled exception in RxUI.</exception> static RxApp() { #if !PORTABLE _taskpoolScheduler = TaskPoolScheduler.Default; #endif Locator.RegisterResolverCallbackChanged(() => { if (Locator.CurrentMutable == null) { return; } Locator.CurrentMutable.InitializeReactiveUI(); }); DefaultExceptionHandler = Observer.Create <Exception>(ex => { // NB: If you're seeing this, it means that an // ObservableAsPropertyHelper or the CanExecute of a // ReactiveCommand ended in an OnError. Instead of silently // breaking, ReactiveUI will halt here if a debugger is attached. if (Debugger.IsAttached) { Debugger.Break(); } MainThreadScheduler.Schedule(() => { #pragma warning disable CA1065 // Avoid exceptions in constructors -- In scheduler. throw new UnhandledErrorException( "An object implementing IHandleObservableErrors (often a ReactiveCommand or ObservableAsPropertyHelper) has errored, thereby breaking its observable pipeline. To prevent this, ensure the pipeline does not error, or Subscribe to the ThrownExceptions property of the object in question to handle the erroneous case.", ex); #pragma warning restore CA1065 }); }); _suspensionHost = new SuspensionHost(); if (ModeDetector.InUnitTestRunner()) { LogHost.Default.Warn("*** Detected Unit Test Runner, setting MainThreadScheduler to CurrentThread ***"); LogHost.Default.Warn("If we are not actually in a test runner, please file a bug\n\n"); LogHost.Default.Warn("ReactiveUI acts differently under a test runner, see the docs\n"); LogHost.Default.Warn("for more info about what to expect"); UnitTestMainThreadScheduler = CurrentThreadScheduler.Instance; return; } LogHost.Default.Info("Initializing to normal mode"); if (_mainThreadScheduler == null) { _mainThreadScheduler = DefaultScheduler.Instance; } }
/// <summary> /// Observe changes to the AppState of a class derived from ISuspensionHost. /// </summary> /// <typeparam name="T">The observable type.</typeparam> /// <param name="item">The suspension host.</param> /// <returns>An observable of the app state.</returns> public static IObservable <T> ObserveAppState <T>(this ISuspensionHost item) where T : class { if (item is null) { throw new ArgumentNullException(nameof(item)); } return(item.WhenAny(suspensionHost => suspensionHost.AppState, observedChange => observedChange.Value) .WhereNotNull() .Cast <T>()); }
/// <summary> /// Get the current App State of a class derived from ISuspensionHost. /// </summary> /// <typeparam name="T">The app state type.</typeparam> /// <param name="item">The suspension host.</param> /// <returns>The app state.</returns> public static T GetAppState <T>(this ISuspensionHost item) { if (item == null) { throw new ArgumentNullException(nameof(item)); } if (item.AppState == null) { throw new NullReferenceException(nameof(item.AppState)); } return((T)item.AppState); }
public override void Run() { base.Run(); IExceptionHandler handler = Locator.Current.GetService <IExceptionHandler>(); if (handler != null) { handler.SetupErrorHandling(); } ISuspensionHost suspension = Locator.Current.GetService <ISuspensionHost>(); if (suspension != null) { suspension.SetupDefaultSuspendResume(); } }
/// <summary> /// /// </summary> /// <typeparam name="T"></typeparam> /// <param name="This"></param> /// <returns></returns> public static IObservable <T> ObserveAppState <T>(this ISuspensionHost This) { return(This.WhenAny(x => x.AppState, x => (T)x.Value) .Where(x => x != null)); }
/// <summary> /// /// </summary> /// <typeparam name="T"></typeparam> /// <param name="This"></param> /// <returns></returns> public static T GetAppState <T>(this ISuspensionHost This) { return((T)This.AppState); }
/// <summary> /// Observe changes to the AppState of a class derived from ISuspensionHost. /// </summary> /// <typeparam name="T">The observable type.</typeparam> /// <param name="item">The suspension host.</param> /// <returns>An observable of the app state.</returns> public static IObservable <T> ObserveAppState <T>(this ISuspensionHost item) where T : class { return(item.WhenAny(x => x.AppState, x => (T)x.Value) .Where(x => x != null)); }