Windows Phone 8.1 应用生命周期

原文: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();
}

 

六、注意

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

时间: 2024-09-20 06:01:06

Windows Phone 8.1 应用生命周期的相关文章

Windows 8 动手实验教程 实验5:进程生命周期管理

动手实验 实验5:进程生命周期管理 2012年9月 简介 进程生命周期管理对构建Windows应用商店应用的开发者来说是需要理解的最重要的概念之一.不同于传统的Windows应用(它们即使在后台仍然继续执行),Windows应用商店应用仅在前台时执行.通常不可见的应用程序被操作系统挂起并且不能被执行直到操作系统将它恢复到前台. 当应用程序被挂起,它仍然在内存中,同时它的所有线程被挂起.只要进程仍然在内存中,当应用程序回到前台时,它将从停止的地方继续执行.要做到这一点开发者不需要做任何工作.然而您

Windows 8风格应用开发入门 三十 应用生命周期管理

开发入门 三十 应用生命周期管理-风格型产品生命周期"> Windows 8 中可以启动多个应用并在其中切换,我们没有必要担心降低系统速 度或消耗电池电量. 因为系统会自动挂起(有时会终止)在后台正在运行的应用.设计良好的应用可 以由系统挂起.终止以及重新启动,并且这些过程看起来该应用一直在运行中. 一.原理 1.当激活了应用时,无论任何原因,系统都会发送 Activated 事件 2.每当用户切换到桌面 或其他应用时,系统都会挂起你的应用,系统会发送Suspending事件 3.每当用户

重新想象 Windows 8 Store Apps (70) - 其它: 文件压缩和解压缩, 与 Windows 商店相关的操作, app 与 web, 几个 Core 的应用, 页面的生命周期和程序的生命周期

原文:重新想象 Windows 8 Store Apps (70) - 其它: 文件压缩和解压缩, 与 Windows 商店相关的操作, app 与 web, 几个 Core 的应用, 页面的生命周期和程序的生命周期 [源码下载] 重新想象 Windows 8 Store Apps (70) - 其它: 文件压缩和解压缩, 与 Windows 商店相关的操作, app 与 web, 几个 Core 的应用, 页面的生命周期和程序的生命周期 作者:webabcd 介绍重新想象 Windows 8

与众不同 windows phone (27) - Feature(特性)之搜索的可扩展性, 程序的生命周期和页面的生命周期, 页面导航, 系统状态栏

原文:与众不同 windows phone (27) - Feature(特性)之搜索的可扩展性, 程序的生命周期和页面的生命周期, 页面导航, 系统状态栏 [索引页][源码下载] 与众不同 windows phone (27) - Feature(特性)之搜索的可扩展性, 程序的生命周期和页面的生命周期, 页面导航, 系统状态栏 作者:webabcd 介绍与众不同 windows phone 7.5 (sdk 7.1) 之特性 搜索的可扩展性 程序的生命周期和页面的生命周期 页面导航 系统状态

微软延长Skylake平台支持Windows 7/8.1生命周期

今年1月,微软宣布包括戴尔.惠普等在内100多款搭载英特尔第六代酷睿Skylake处理器的OEM设备将于2017年7月17日之前终止对Windows 7/8.1系统的支持,在此之后运行Skylake处理器的老版本Windows系统只能接受关键安全更新.而今天微软对Skylake支持策略进行调整,延长系统完全支持寿命周期至2018年7月17日,延长1年时间. 在截止日期之后,运行Skylake处理器的老版本Windows系统依然只能接受关键安全更新,直到操作系统结束生命周期.Windows 7系统

用三张图片详解Asp.Net 全生命周期

转自http://www.cnblogs.com/yun98/archive/2011/11/16/2251216.html 下面我们使用三张图片解析ASP.net的整个生命周期,我总感觉使用图片更加的清楚的说明这种问题,所以使用的这样方式   说明: 1  第一张图片从全局说明从客户端发出一个Request请求,服务器windows内核中的HTTP.SYS组件接收该请求开始到IIS处理完该请求并响应到客户端结束. 2  第二张图片为图1中Http处理管线的详细步骤 3  第三张图片为图2Htt

温故而知新:HttpApplication,HttpModule,HttpContext及Asp.Net页生命周期

IIS在接到一个新的http请求后,最终会调用asp.net_isapi.dll的ISAPI扩展(特指IIS6.0环境,iis7.0的应用程序池默认为集成方式,相对有所变化),然后传递到httpRuntime Pipe(http运行时管道),Asp.Net这时才开始运行(即HttpRunTime是Asp.Net真正的入口),HttpRunTime会为每个asp.net应用自动创建一个HttpApplication的实例,而该实例中又包含以下属性:   注1 Application -->相当于传

自定义Unity对象生命周期管理集成ADO.NET Entity Framework

在Unity中,从Unity 取得的实例为 Transient.如果你希望使用多线程方式,就需要在组成时使用lifecycle参数,这时候取出的组件就不再是同一个了.在Unity IOC中,它支持我们对于组件的实例进行控制,也就是说我们可以透明的管理一个组件拥有多少个实例.Unity IOC容器提供了如下几种生命处理方式:# Singleton:一个组件只有一个实例被创建,所有请求的客户使用程序得到的都是同一个实例.# Transient:这种处理方式与我们平时使用new的效果是一样的,对于每次

2000条你应知的WPF小姿势 基础篇&lt;22-27 WPF生命周期, 基础类等&gt;

原文:2000条你应知的WPF小姿势 基础篇<22-27 WPF生命周期, 基础类等> 端午长假在家陪着女朋友, 幸福感满满,生活对于一只饱经忧患的程序猿来说也是非常重要的,也就暂时没有更新博客.休假结束,回归奋斗的日子了,开始继续更新WPF系列. 在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C#  和 2,000 Things You Should Kn