• 06,Windows Phone 8程序的生命周期


    内容预告:

    • 启动(Launching)和关闭(Closing)
    • Deactviating和Activating
    • Dormant和Tombstoned
    • 用模拟器模拟这些事件
    • 空闲检测
    • 快速恢复
    • 生命周期规划
    • 页面导航和后退栈

    Windows Phone应用程序在不同的状态间过渡的图示如下:

    程序从点击开始屏幕的图标上启动,用户可以关闭程序,系统可能挂起你的程序(在程序失去焦点的时候),挂起的程序可能会进入墓碑,程序可能从挂起状态激活。
    当用户启动一个新的程序的实例时,之前的挂起状态会丢失。比如当运行一个程序时,点到了Home键,再点击开始屏幕的图标上启动程序,按Home键之前挂起状态会丢失,正确的做法是按住Back键不动选择那个程序恢复状态。
    在Windows Phone 8中,可以用快速恢复功能(Fast Application Resume)重新启动挂起的程序。

    应用程序的生命周期事件:

    private void Application_Launching(object sender, LaunchingEventArgs e)
    {
    }

    Windows Phone应用程序环境会通过一些事件通知上述状态,在项目模板里的App.xaml里订阅了事件,并在App.xaml.cs处理了,初使化情况下处理逻辑是空的。

    启动和关闭:Launching 和 Closing
    当程序启动时,Applcation_Launching会被调用,程序结束时,Application_Closing会被调用,调试器在程序停止后还会继续运行,所以需要手动结束。

    程序的Deactivation和Reactivation:
    出于省电的考虑,任何时间只有一个程序运行在前台,用户可以deactivate程序也可以reactivate它们,程序需要处理Activated和Deactivated事件。

    程序的休眠(Dormant):
    用户可以随时休眠应用程序,然后运行其他程序,这个时候Application_Deactivated函数被调用,电话突然打来时,程序也会休眠,锁屏时程序也会休眠一段时间。用户也可以恢复休眠的程序。但是不保证一定能从休眠状态中恢复。

    从休眠中重新激活:

    处理休眠:
    当程序被休眠时必须尽可能地保存数据因为程序可能会关闭,如果用户不再通过长按Back回到那个程序,Application_Deactivated就相当于Application_Closing了。
    你的程序有5秒钟的机会清理现场(保存数据),之后程序会被从内存中清除掉。当程序长按Back恢复时,它会自动恢复到Deactivated时的那个页面,这是操作系统帮我们做的,但是,页面的内容并不会自动保存。

    从休眠到墓碑:

    一个程序会和其他程序一起在内存里休眠,如果操作系统的内存不够用了会释放最先休眠的程序的缓存状态,这个过程叫做“墓碑化”。
    页面导航历史和缓存状态都被墓碑了的程序维护着。
    当一个休眠了的程序恢复时,缓存状态会重新加载,程序会万利到它离开之前的那个页面。
    当一个墓碑了的程序恢复时,它会重启离开之前的页面,但是所有的程序状态会丢失,你需要重新加载。
    一个程序可以决定从哪个状态激活。

    从墓碑状态重新激活:

    从休眠还是墓碑恢复的?可以在恢复前做一个判断

    private void Application_Activated(object sender, ActivatedEventArgs e)
    {
        if (e.IsApplicationInstancePreserved)
        {
            // Dormant - objects in memory intact
        }
        else
        {
            // Tombstoned - need to reload
        }
    }


    状态和墓碑:

    当程序从休眠恢复时,程序会准确地恢复到离开时的页面,所有的对象和它们的状态都在内存里,你可能需要写一些逻辑来重置依赖于时间或网络的调用代码。
    当程序从墓碑恢复时,程序只会恢复到离开时的页面,但所有对象和它们的状态都丢失了,所以需要重新加载控件的数据,这就是为什么需要保存状态,程序从内存中移除了系统也维护着状态。
    当程序的一个新的实例启动时,状态是空的。如果一个先前的程序挂起了,那么那个程序存储的状态字典会丢失。

    状态字典:

    PhoneApplicationService.Current.State["Url"] = "www.robmiles.com";

    休眠程序的状态信息存在一个状态字典里,如上述代码。
    可以在Application_Deactivated函数里存储,然后在页面激活时读取。
    所以Application_Deactivated有两件事情要做,保存数据以防程序不能重新激活,保存状态数据以保证程序恢复到正确的状态。

    调试墓碑状态:

    当休眠的时候,可以在Visual Studio里设置强制程序墓碑化(从内存中移除)。
    你应该把这个做为测试引擎的一部分。
    你也可以用模拟器操作锁屏,也可以让程序进入休眠。

     模拟器操作面板:

    模拟器可以模拟锁屏和解锁,会让程序进入Deactivated和Activated状态。

    空闲处理:
    Windows Phone操作系统会检测到程序的空闲状态,当手机进入空闲状态,会让手机锁屏。
    用户可以配置多长时间后开始检测,也可以关闭检测。
    当程序被检测到是空闲的话,将会进行Deactivated状态,当用户解锁后,手机会Activated。
    程序可以禁止检测空闲,那样就可以在锁屏下运行了。

    PhoneApplicationService.Current.ApplicationIdleDetectionMode =  IdleDetectionMode.Disabled;

    这样即使手机锁屏了也会有什么Activated和Deactivated了。
    但如果是用户按了Start键还是会deactivated。
    禁止空闲检测也不能同时运行两个程序。

    检测遮挡事件:比如toast消息,锁屏,来电等。

    App.RootFrame.Obscured += RootFrame_Obscured;
    
    ...
    
    void RootFrame_Obscured(object sender, ObscuredEventArgs e)
    {
    }

    程序可以订阅遮挡事件,也可以订阅遮挡移除的事件。

    导航和后退栈:

    Windows Phone程序的导航模型使用起来很方便,可以通过链接到其他页面,可以通过后退键到上一个页面。
    系统维护了一个后退的栈,当跳转到另一个页面时,之前的页面地址会被压入栈,当后退时,当前页面会出栈。

    后退栈和Activated/Deactivated:

    当程序deactivated时,系统会保持后退栈,包括当前的页面,但只有页面地址被保存,内容并不保存。
    程序必须在OnNavigatedTo和OnNavigatedFrom事件里构建页面和保存数据。

    从不同的地方进入程序:

    一般情况下程序会在运行时显示首页,而且这个首页会被压入栈,且后退时会回到首页。
    有些情况下可以不用进入首页,比如(第二磁贴,提醒,文件关联,搜索,钱包,语音),但同时带来新的问题

    后退栈的问题:

    有这样一个场景,当用户在后退栈里忆压入很多页面时,进入相册选择了相片,然后在相册界面按后退键,会首先回到程序进入相册前的最后一个页面,再后退,程序会退出。
    这里需要特殊处理后退栈,比如模拟后退栈,因为在页面从后退栈清除时会有一个事件触发。

    模拟后退栈:

    private void PurgeBackStackButton_Click(object sender, RoutedEventArgs e)
    {
        while (NavigationService.CanGoBack)
            NavigationService.RemoveBackEntry();
    }

    程序可以质问后退栈是否可以后退,也可以把栈内所有页面清除光。
    程序可以枚举后退栈的所有页面,但不能将页面压栈。

    OnRemovedFromJournal:

    protected override void OnRemovedFromJournal(JournalEntryRemovedEventArgs e)
    {
        base.OnRemovedFromJournal(e);
    
    }

    在程序运动时,一个页面希望能够从子页面返回,但如果它从后退栈移除后就不是这个流程了。
    可以用OnRemovedFromJournal事件捕获当本页面从后退栈里移除时做一些处理。

    快速恢复FAR(Fast Application Resume):这个功能可以让程序在激活时速度更快。需要手动在WMAppManifest.xml里编辑

    <Tasks>
        <DefaultTask  Name ="_default" NavigationPage="MainPage.xaml">
          <BackgroundExecution>
            <ExecutionType Name="LocationTracking" />
          </BackgroundExecution>
        </DefaultTask>
    </Tasks>

    FAR的两种下场:
    通过把程序注册为LocationTracking可以实现FAR,但LocationTracking我们未必会用。

    如果程序中用到了定位的类,那么当程序deactivated时会继续一直在后台运行,如果重新运行程序,程序会快速从当前休眠的状态恢复。

    如果程序中没用定位的类,那么那么当程序deactivated时,程序像平常一样,如果重新运行程序,程序会从之前休眠的状态恢复。

    标准的重新启动程序如上图所示:

    真正的有后台定位的行为如上图所示:

    后台无定位程序在运行的FAR程序如上图所示:

    为什么不在所有程序上用FAR?

    因为用的时候要非常小心页面导航的用户体验,
    非FAR的程序中,如果启动程序到page2,那么page2是后退栈里唯一的页面,按后退会退出程序。
    在FAR的程序中,如果启动程序到page2,但是之前挂起的程序的后退栈里有mainpage,page1,page2,page3,那么当运行新程序实例时,按后退键的话,程序会以mainpgae,pgae1,page2,page3,page2的程序退出。

    FAR程序中主磁贴的行为:

    用户在点击程序的磁贴后,程序会进入主页面,非FAR的程序会这样,之前没有挂起实例的FAR的程序也会这样。
    如果是恢复到程序呢?应该是怎么样?恢复到首页还是最后一个页面?如果恢复到最后一页那怎么进入首页?这里有一个建议是在页面上加一个回到首页的链接。

    检测FAR程序的恢复行为:

    在真正的有后台运行定位的程序中,当程序被送到后台后会继续运行,程序会触发PhoneApplicationService.RunningInBackground事件而不是Application_Deactivated事件。
    当FAR程序重新启动时,会以
    NavigationMode.Reset的方式导航到后退栈最顶部的页面,然后会以NavigationMode.New的方式定位到新启动的URL的页面,可以决定是否上传页面的后退栈,或取消导航到新页面。

    清除FAR程序之前的实例运行的页面:在App.xaml.cs里加入

    
    

    private void InitializePhoneApplication()
     {
         ...
         // Handle reset requests for clearing the backstack
         RootFrame.Navigated += CheckForResetNavigation;

    
    

         ...
     }

     private void CheckForResetNavigation(object sender, NavigationEventArgs e)
     {
         // If the app has received a 'reset' navigation, then we need to check
         // on the next navigation to see if the page stack should be reset
         if (e.NavigationMode == NavigationMode.Reset)
             RootFrame.Navigated += ClearBackStackAfterReset;
     }

     private void ClearBackStackAfterReset(object sender, NavigationEventArgs e)
     {
         // Unregister the event so it doesn't get called again
         RootFrame.Navigated -= ClearBackStackAfterReset;
         // Only clear the stack for 'new' (forward) and 'refresh' navigations
         if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh)
             return;
         // For UI consistency, clear the entire page stack
         while (RootFrame.RemoveBackEntry() != null)   { } // do nothing  
     }

  • 相关阅读:
    一轮项目冲刺9
    一轮项目冲刺8
    一轮项目冲刺7
    一轮项目冲刺6
    一轮项目冲刺5
    一轮项目冲刺4
    一轮项目冲刺3
    一轮项目冲刺2
    一轮项目冲刺1
    移山小分队---每日记录01
  • 原文地址:https://www.cnblogs.com/icuit/p/2815051.html
Copyright © 2020-2023  润新知