zoukankan      html  css  js  c++  java
  • Windows Phone 8.1 应用生命周期

    一、“后退键”不会终止应用

    关于 Windows Phone 8.1 的应用生命周期,第一个要知道的关键就是:“后退键”不会终止应用

    在 8.0 时代,不断的按下“后退键”就可以完全的关闭并且终止应用,但在 8.1 中,这样的行为只会让应用处在 Suspended(挂起)状态,可以通过长按“后退键”进入多任务界面查看。

    那如果还想像 8.0 一样终止应用呢?(虽然不推荐也没有必要)可以在多任务界面点击应用右上角的“叉叉”或者向下滑。

     

    二、应用生命周期

    应用的三个状态分别是:

    A:NotRunning

    也就是还没开启过应用,在多任务界面没有该应用时。

    B:Running

    在屏幕上显示的应用就是 Running 状态,同时只会有 1 个应用处于 Running 状态。

    C:Suspended

    不在屏幕上显示并能在多任务界面查看的应用则处于 Suspended(挂起)状态。

     

    三种状态间切换的操作:

    (1)NotRunning -> Running

    要从 NotRunning 切换到 Running 状态,其实也就是开启应用,可通过点击应用磁贴、应用间协议启动、Cortana等方式。

    在状态的切换过程中会触发 OnLaunched 事件。

    (2)Running -> Suspended

    当应用不再占据屏幕时则从 Running 切换到 Suspended 状态,可以是“Win”键、“返回键”,有电话打来时也会挂起。

    在状态的切换过程中会触发 OnSuspending 事件。

    (3)Suspended -> Running

    如果在应用挂起状态时没有因为某些原因(比如内存不足)导致应用终止的话,点击磁贴或者多任务切换都会让应用从 Suspender 返回到 Running 状态。

    在状态的切换过程中会依次触发 OnResuming 和 OnLaunched 事件。

    (4)Suspended -> NotRunning

    如果在应用挂起状态时因为某些原因(比如内存不足)导致应用终止的话,则会从 Suspended 变成 NotRunning 状态。

    在这过程不会触发任何事件。

     

    三、OnSuspending

    因为应用在挂起状态时,并不能预测应用是否会因为某些原因(比如内存不足)而终止,而在这终止过程中也没有事件让开发者处理应用数据,所以只能在应用将要挂起时准备。因此 OnSuspending 事件变得十分重要。

    若要使用 OnSuspending 方法则先要在构造函数中添加对其的引用:

    public App()
    {
      this.InitializeComponent();
      this.Suspending += OnSuspending;
    }

    而在 OnSuspending 方法中可以根据需要保存页面数据,比如输入框内的文本、页面导航历史等,可以通过保存在应用独立存储中或利用 NavigationHelper 和 SuspensionManager 类等:

    async void OnSuspending(object sender, SuspendingEventArgs e)
    {
        SuspendingDeferral deferral = e.SuspendingOperation.GetDeferral();
    
        await this.SaveStateToLocalFile(Data.Value);
    
    await SuspensionManager.SaveAsync();
    
        deferral.Complete();
    }

    如果只想保存某个页面的信息则可以在 SaveState 中保存:

    private void NavigationHelper_SaveState(object sender, SaveStateEventArgs e)
    {
         e.PageState["isEditing"] = true;
         e.PageState["currentText"] = this.viewModel.DataItem.Title;
    }

    NavigationHelper 和 SuspensionManager 类是添加基本页时 Visual Studio 自动添加的:

    public class NavigationHelper : DependencyObject
    {
        private Page Page { get; set; }
        private Frame Frame { get { return this.Page.Frame; } }
    
        public NavigationHelper(Page page)
        {
            this.Page = page;
    
            this.Page.Loaded += (sender, e) =>
            {
    WINDOWS_PHONE_APP
                Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
    e
    
    if
            };
    
            this.Page.Unloaded += (sender, e) =>
            {
    WINDOWS_PHONE_APP
                Windows.Phone.UI.Input.HardwareButtons.BackPressed -= HardwareButtons_BackPressed;
    e
    
    if
            };
        }
    
        #region Navigation support
    
            RelayCommand _goBackCommand;
            RelayCommand _goForwardCommand;
    
            public RelayCommand GoBackCommand
            {
                get
                {
                    if (_goBackCommand == null)
                    {
                        _goBackCommand = new RelayCommand(
                            () => this.GoBack(),
                            () => this.CanGoBack());
                    }
                    return _goBackCommand;
                }
                set
                {
                    _goBackCommand = value;
                }
            }
    
            public RelayCommand GoForwardCommand
            {
                get
                {
                    if (_goForwardCommand == null)
                    {
                        _goForwardCommand = new RelayCommand(
                            () => this.GoForward(),
                            () => this.CanGoForward());
                    }
                    return _goForwardCommand;
                }
            }
    
            public virtual bool CanGoBack()
            {
                return this.Frame != null && this.Frame.CanGoBack;
            }
    
            public virtual bool CanGoForward()
            {
                return this.Frame != null && this.Frame.CanGoForward;
            }
    
            public virtual void GoBack()
            {
                if (this.Frame != null && this.Frame.CanGoBack) this.Frame.GoBack();
            }
    
            public virtual void GoForward()
            {
                if (this.Frame != null && this.Frame.CanGoForward) this.Frame.GoForward();
            }
    
    #if WINDOWS_PHONE_APP
            private void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
            {
                if (this.GoBackCommand.CanExecute(null))
                {
                    e.Handled = true;
                    this.GoBackCommand.Execute(null);
                }
            }
    #else
            private void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher sender,
                AcceleratorKeyEventArgs e)
            {
                var virtualKey = e.VirtualKey;
    
                if ((e.EventType == CoreAcceleratorKeyEventType.SystemKeyDown ||
                    e.EventType == CoreAcceleratorKeyEventType.KeyDown) &&
                    (virtualKey == VirtualKey.Left || virtualKey == VirtualKey.Right ||
                    (int)virtualKey == 166 || (int)virtualKey == 167))
                {
                    var coreWindow = Window.Current.CoreWindow;
                    var downState = CoreVirtualKeyStates.Down;
                    bool menuKey = (coreWindow.GetKeyState(VirtualKey.Menu) & downState) == downState;
                    bool controlKey = (coreWindow.GetKeyState(VirtualKey.Control) & downState) == downState;
                    bool shiftKey = (coreWindow.GetKeyState(VirtualKey.Shift) & downState) == downState;
                    bool noModifiers = !menuKey && !controlKey && !shiftKey;
                    bool onlyAlt = menuKey && !controlKey && !shiftKey;
    
                    if (((int)virtualKey == 166 && noModifiers) ||
                        (virtualKey == VirtualKey.Left && onlyAlt))
                    {
                        e.Handled = true;
                        this.GoBackCommand.Execute(null);
                    }
                    else if (((int)virtualKey == 167 && noModifiers) ||
                        (virtualKey == VirtualKey.Right && onlyAlt))
                    {
                        e.Handled = true;
                        this.GoForwardCommand.Execute(null);
                    }
                }
            }
    
            private void CoreWindow_PointerPressed(CoreWindow sender,
                PointerEventArgs e)
            {
                var properties = e.CurrentPoint.Properties;
    
                if (properties.IsLeftButtonPressed || properties.IsRightButtonPressed ||
                    properties.IsMiddleButtonPressed) return;
    
                bool backPressed = properties.IsXButton1Pressed;
                bool forwardPressed = properties.IsXButton2Pressed;
                if (backPressed ^ forwardPressed)
                {
                    e.Handled = true;
                    if (backPressed) this.GoBackCommand.Execute(null);
                    if (forwardPressed) this.GoForwardCommand.Execute(null);
                }
            }
    #endif
    
            #endregion
    
        #region Process lifetime management
    
            private String _pageKey;
            public event LoadStateEventHandler LoadState;
            public event SaveStateEventHandler SaveState;
    
            public void OnNavigatedTo(NavigationEventArgs e)
            {
                var frameState = SuspensionManager.SessionStateForFrame(this.Frame);
                this._pageKey = "Page-" + this.Frame.BackStackDepth;
    
                if (e.NavigationMode == NavigationMode.New)
                {
                    var nextPageKey = this._pageKey;
                    int nextPageIndex = this.Frame.BackStackDepth;
                    while (frameState.Remove(nextPageKey))
                    {
                        nextPageIndex++;
                        nextPageKey = "Page-" + nextPageIndex;
                    }
    
                    if (this.LoadState != null)
                    {
                        this.LoadState(this, new LoadStateEventArgs(e.Parameter, null));
                    }
                }
                else
                {
                    if (this.LoadState != null)
                    {
                        this.LoadState(this, new LoadStateEventArgs(e.Parameter, (Dictionary<String, Object>)frameState[this._pageKey]));
                    }
                }
            }
    
            public void OnNavigatedFrom(NavigationEventArgs e)
            {
                var frameState = SuspensionManager.SessionStateForFrame(this.Frame);
                var pageState = new Dictionary<String, Object>();
                if (this.SaveState != null)
                {
                    this.SaveState(this, new SaveStateEventArgs(pageState));
                }
                frameState[_pageKey] = pageState;
            }
    
            #endregion
    }
    
    
    public delegate void LoadStateEventHandler(object sender, LoadStateEventArgs e);
    public delegate void SaveStateEventHandler(object sender, SaveStateEventArgs e);
    
    public class LoadStateEventArgs : EventArgs
    {
        public Object NavigationParameter { get; private set; }
        public Dictionary<string, Object> PageState { get; private set; }
    
        public LoadStateEventArgs(Object navigationParameter, Dictionary<string, Object> pageState)
            : base()
        {
            this.NavigationParameter = navigationParameter;
            this.PageState = pageState;
        }
    }
    
    public class SaveStateEventArgs : EventArgs
    {
        public Dictionary<string, Object> PageState { get; private set; }
        public SaveStateEventArgs(Dictionary<string, Object> pageState)
            : base()
        {
            this.PageState = pageState;
        }
    }
    NavigationHelper
    internal sealed class SuspensionManager
        {
            private static Dictionary<string, object> _sessionState = new Dictionary<string, object>();
            private static List<Type> _knownTypes = new List<Type>();
            private const string sessionStateFilename = "_sessionState.xml";
    
            public static Dictionary<string, object> SessionState
            {
                get { return _sessionState; }
            }
    
            public static List<Type> KnownTypes
            {
                get { return _knownTypes; }
            }
    
            public static async Task SaveAsync()
            {
                try
                {
                    foreach (var weakFrameReference in _registeredFrames)
                    {
                        Frame frame;
                        if (weakFrameReference.TryGetTarget(out frame))
                        {
                            SaveFrameNavigationState(frame);
                        }
                    }
    
                    MemoryStream sessionData = new MemoryStream();
                    DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary<string, object>), _knownTypes);
                    serializer.WriteObject(sessionData, _sessionState);
    
                    StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(sessionStateFilename, CreationCollisionOption.ReplaceExisting);
                    using (Stream fileStream = await file.OpenStreamForWriteAsync())
                    {
                        sessionData.Seek(0, SeekOrigin.Begin);
                        await sessionData.CopyToAsync(fileStream);
                    }
                }
                catch (Exception e)
                {
                    throw new SuspensionManagerException(e);
                }
            }
    
            public static async Task RestoreAsync(String sessionBaseKey = null)
            {
                _sessionState = new Dictionary<String, Object>();
    
                try
                {
                    StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(sessionStateFilename);
                    using (IInputStream inStream = await file.OpenSequentialReadAsync())
                    {
                        DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary<string, object>), _knownTypes);
                        _sessionState = (Dictionary<string, object>)serializer.ReadObject(inStream.AsStreamForRead());
                    }
    
                    foreach (var weakFrameReference in _registeredFrames)
                    {
                        Frame frame;
                        if (weakFrameReference.TryGetTarget(out frame) && (string)frame.GetValue(FrameSessionBaseKeyProperty) == sessionBaseKey)
                        {
                            frame.ClearValue(FrameSessionStateProperty);
                            RestoreFrameNavigationState(frame);
                        }
                    }
                }
                catch (Exception e)
                {
                    throw new SuspensionManagerException(e);
                }
            }
    
            private static DependencyProperty FrameSessionStateKeyProperty =
                DependencyProperty.RegisterAttached("_FrameSessionStateKey", typeof(String), typeof(SuspensionManager), null);
            private static DependencyProperty FrameSessionBaseKeyProperty =
                DependencyProperty.RegisterAttached("_FrameSessionBaseKeyParams", typeof(String), typeof(SuspensionManager), null);
            private static DependencyProperty FrameSessionStateProperty =
                DependencyProperty.RegisterAttached("_FrameSessionState", typeof(Dictionary<String, Object>), typeof(SuspensionManager), null);
            private static List<WeakReference<Frame>> _registeredFrames = new List<WeakReference<Frame>>();
    
            public static void RegisterFrame(Frame frame, String sessionStateKey, String sessionBaseKey = null)
            {
                if (frame.GetValue(FrameSessionStateKeyProperty) != null)
                {
                    throw new InvalidOperationException("Frames can only be registered to one session state key");
                }
    
                if (frame.GetValue(FrameSessionStateProperty) != null)
                {
                    throw new InvalidOperationException("Frames must be either be registered before accessing frame session state, or not registered at all");
                }
    
                if (!string.IsNullOrEmpty(sessionBaseKey))
                {
                    frame.SetValue(FrameSessionBaseKeyProperty, sessionBaseKey);
                    sessionStateKey = sessionBaseKey + "_" + sessionStateKey;
                }
    
                frame.SetValue(FrameSessionStateKeyProperty, sessionStateKey);
                _registeredFrames.Add(new WeakReference<Frame>(frame));
    
                RestoreFrameNavigationState(frame);
            }
    
            public static void UnregisterFrame(Frame frame)
            {
                SessionState.Remove((String)frame.GetValue(FrameSessionStateKeyProperty));
                _registeredFrames.RemoveAll((weakFrameReference) =>
                {
                    Frame testFrame;
                    return !weakFrameReference.TryGetTarget(out testFrame) || testFrame == frame;
                });
            }
    
            public static Dictionary<String, Object> SessionStateForFrame(Frame frame)
            {
                var frameState = (Dictionary<String, Object>)frame.GetValue(FrameSessionStateProperty);
    
                if (frameState == null)
                {
                    var frameSessionKey = (String)frame.GetValue(FrameSessionStateKeyProperty);
                    if (frameSessionKey != null)
                    {
                        if (!_sessionState.ContainsKey(frameSessionKey))
                        {
                            _sessionState[frameSessionKey] = new Dictionary<String, Object>();
                        }
                        frameState = (Dictionary<String, Object>)_sessionState[frameSessionKey];
                    }
                    else
                    {
                        frameState = new Dictionary<String, Object>();
                    }
                    frame.SetValue(FrameSessionStateProperty, frameState);
                }
                return frameState;
            }
    
            private static void RestoreFrameNavigationState(Frame frame)
            {
                var frameState = SessionStateForFrame(frame);
                if (frameState.ContainsKey("Navigation"))
                {
                    frame.SetNavigationState((String)frameState["Navigation"]);
                }
            }
    
            private static void SaveFrameNavigationState(Frame frame)
            {
                var frameState = SessionStateForFrame(frame);
                frameState["Navigation"] = frame.GetNavigationState();
            }
        }
    public class SuspensionManagerException : Exception
        {
            public SuspensionManagerException()
            {
            }
    
            public SuspensionManagerException(Exception e)
                : base("SuspensionManager failed", e)
            {
    
            }
        }
    SuspensionManager

    四、OnResuming

    既然在 OnSuspending 和 SaveState 方法中保存了必要数据,就可以在 OnResuming 和 LoadState 方法中获取之前保存的数据:

    void OnResuming(object sender, object e)
    {
        Data.Value += this.CalculateOffsetTimeInDecimalSeconds(this.suspensionTime);
    }
    private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
    {
        if ((e.PageState != null) && e.PageState.ContainsKey("isEditing"))
        {
            this.viewModel.SetEditMode();
            this.viewModel.DataItem.Title = e.PageState["currentText"] as string;
        }
    }

    五、OnLaunched

    首先,在 OnLaunched 方法中可以通过 e.PreviousExecutionState 了解到应用之前的状态。

    状态包括:

    (1)CloseByUser:被用户主动在多任务界面中关闭

    (2)NotRunning:没有启动过

    (3)Running:启动中

    (4)Terminated:挂起状态时因内存不足被系统终止

    (5)Suspended:挂起状态

    因此,可以通过对此的判断,根据不同情况处理应用:

    protected async override void OnLaunched(LaunchActivatedEventArgs e)
    {
      Frame rootFrame = Window.Current.Content as Frame;
    
      if (rootFrame == null)
      {
        rootFrame = new Frame();
    
        SuspensionManager.RegisterFrame(rootFrame, "AppFrame");
    
        rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0];
    
        if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
        {
          try
          {
            await SuspensionManager.RestoreAsync();
          }
          catch (SuspensionManagerException)
          {
          }
        }
    
        Window.Current.Content = rootFrame;
      }
    
      if (rootFrame.Content == null)
      {
        rootFrame.Navigate(typeof(MainPage), e.Arguments);
      }
    
      Window.Current.Activate();
    }

    六、注意

    以上的方法尽量使用异步操作,不要进行大量的复杂操作。

  • 相关阅读:
    MySQL5.7安装详细教程
    Java之GUI编程
    Java基础
    生成JavaDoc文档
    SpringtMVC运行流程:@RequestMapping 方法中的 Map、HttpServletRequest等参数信息是如何封装和传递的(源码理解)
    SpringCache @Cacheable 在同一个类中调用方法,导致缓存不生效的问题及解决办法
    Spring源码学习:第1步--在Spring源码中添加最简单的Demo代码
    Spring源码学习:第2步--使用SLF4j+Log4j日志框架替换掉其自身的commons-logging日志框架
    Spring源码学习:第0步--环境准备
    JasperReport报表
  • 原文地址:https://www.cnblogs.com/xiaoshi3003/p/3752895.html
Copyright © 2011-2022 走看看