WP7应用软件生命周期与导航.docx
《WP7应用软件生命周期与导航.docx》由会员分享,可在线阅读,更多相关《WP7应用软件生命周期与导航.docx(18页珍藏版)》请在冰点文库上搜索。
![WP7应用软件生命周期与导航.docx](https://file1.bingdoc.com/fileroot1/2023-5/2/15a4a35c-f594-44f6-a86d-9383795fdc99/15a4a35c-f594-44f6-a86d-9383795fdc991.gif)
WP7应用软件生命周期与导航
WP7应用软件生命周期与导航
应用软件生命周期与导航
前言
如果在以往,您有用过之前的Mobile操作系统,像是WM5.x、WM6.x,是允许你在同时间执行很多应用程序;而应用程序的默认行为,在Form的右上角是一个『X』的按钮,按钮按下去之后,应用程序是躲到了背景,仍在继续在执行;而到了WindowsPhone7,这样的行为模式变更了,在前景一次只能执行一个应用程序,而原先的应用程序发生了什么事?
这就是本篇要跟各位介绍的;而第二个部分是在应用程序中,可能会存在好几个页面,而彼此间要怎么传递数据呢?
这都是今天会谈论到的议题,那么接下来就开始今天的介绍
议程
∙Applicationlifecycle
∙PageNavigation
∙在页面中传递数据
∙Idledetection
Applicationlifecycle
由于在WindowsPhone7中,应用程序的运作方式跟以往的Mobile系列不同,所以在开发应用程序时要留意有关生命周期的事件,以便在需要的地方加以处理;事件的种类会有
∙Launching
∙Closing
∙Activated
∙Deactivated
而这些事件是在甚么时候会发生呢?
下面先来看看第一种状况
应用程序『第一次的启动』一定是由首页的Tile或是由应用程序行表中启动,而启动之后便会产生新的应用程序实例,接着就会进入到Launching事件中;在Launching事件中您可以做一些初始化的动作,需要特别注意的是在Launching事件中,不适合去做长时间的动作,因为Launching事件是发生在页面显示之前,所以在Launching事件没有完成之前,页面都是看不到的,整个屏幕都会是黑黑的一片,所以执行长时间的作业的话,是很容易被误认为应用程序停止响应或是其他的异常情形,这是不好的。
经过Launching的事件之后,应用程序的第一个页面就会显示出来,这时候会进入到应用程序执行中(Running)的状态,而在应用程序的第一个页面时,如果使用者按下返回键,这个时候就会直接引发Closing的事件,Closing事件之后就会把应用程序整个关闭了。
那么,如果在应用程序的第一个页面中,使用者按下了开始钮(
),那这时候呢?
关闭应用程序吗?
不,这时候应用程序会进入tombstoning,之后移到背景,让我们来看看下一张图
当在第一个页面中,使用者按下开始钮,这个时候应用程序便会进入Deactivated的事件,之后便进入tombstoning的状态,也就是整个应用程序会停止运作,这跟之前的Mobile5.x/6.x是有很大的不同的。
而在Deactivated事件之后,使用者这时候可能会执行其他的应用程序或进行其他的操作,之后可能会按下返回键回到应用程序的执行,这个时候就会进入Activated事件,Activated事件处理完毕之后,便会回到执行中的状态;那在这两个事件中,要处理甚么呢?
您可以在这个事件中去储存一些暂时性的数据,而这些数据同时又是属于整个应用程序会使用到的,就可以在这些事件中去处理。
Deactivated事件还有个地方需特别注意,所有在Deactivated事件中处理的事情,必需要在10秒钟之内处理完毕,不然的话系统会强制的中止你的应用程序,而假设发生这种状况的话,程序是被整个关闭,按下返回键是不会回到应用程序中的,这点必须特别留意。
举个简单的例子,例如说一个很简单的游戏程序,程序中会有总分数的纪录,像是下面左图样子,现在是50分,那如果不小心按到开始钮或是其他的原因,离开了应用程序,再返回的时候,糟糕..这时候会像下面右图一样,变成0分了;如果没有适当的去处理这个部份,那对使用者来说是会觉得很疑惑,而且不是一个好的应用程序的。
这个时候就可以处理Deactivated、Activated事件,在相关的事件中去做储存的事件,举个简单的例子;笔者首先在App.xaml.cs中加入一个HighScore的全局变量
publicstaticintHighScore;
之后在App.xaml.cs中处理相关的事件(Applicationlifecycle相关的事件在App.xaml.cs中都可以找到)
//Codetoexecutewhentheapplicationisactivated(broughttoforeground)
//Thiscodewillnotexecutewhentheapplicationisfirstlaunched
privatevoidApplication_Activated(objectsender,ActivatedEventArgse)
{
objecttmp=0;
if(PhoneApplicationService.Current.State.TryGetValue("Score",outtmp))
{
App.HighScore=(int)tmp;
}
else
App.HighScore=0;
}
//Codetoexecutewhentheapplicationisdeactivated(senttobackground)
//Thiscodewillnotexecutewhentheapplicationisclosing
privatevoidApplication_Deactivated(objectsender,DeactivatedEventArgse)
{
PhoneApplicationService.Current.State["Score"]=App.HighScore;
}
最后,在MainPage.xaml.cs中,Loaded事件中,把值给读出来显示
privatevoidPhoneApplicationPage_Loaded(objectsender,RoutedEventArgse)
{
tbScore.Text=App.HighScore.ToString();
}
这样子,不管是不小心误触到其他按键或者是其他原因离开了应用程序都可以正常的保留住想要保留的数据了。
而在上面的程序代码中,您会看到PhoneApplicationService.Curent.State,这是一个实做IDictionary的类别,使用时要加入Microsoft.Phone.Shell的命名空间,之后就可以它用来储存一些应用程序中的数据。
注:
应用程序执行中,用户按下开始钮,或是执行Lanucher/Chooser、拍照等等,或是一段时间没有使用而进入锁定;只要是离开应用程序本身,就会开始进入Deactivated事件
PageNavigation
在刚刚我们看过了应用程序的生命周期,那么页面呢?
紧接着就来看看在页面显示的过程中,以及在页面中去巡览的时候,应用程序是如何处理这些事件的;在这边需要注意的是件有
∙Loaded
每一次页面的载入完成时,都会引发Loaded事件
∙Unloaded
当从这个页面要巡览到另外一个页面时,就会引发Unload事件
∙OnNavigatedFrom
当利用NavigationService,要从页面离开时会引发OnNavigatedForm事件,使用时必须要覆写Page事件
∙OnNavigatedTo
当利用NavigationService,寻览到新的页面时,会引发新页面的OnNavigatedTo事件,使用时必须要覆写Page事件
其中如果要处理OnNavigatedTo、OnNavigatedForm事件是必须利用覆写的方式来使用,而事件发生的顺序会是OnNavigatedToàLoadàOnNavigatedFormàUnLoaded。
而在Page的这些事件中,要处理甚么动作呢?
在页面相关的事件中,要处理的是必须要储存一些暂时性的数据,以便在巡览的过程中使用;以及在页面中传递数据等动作。
当要进行页面的巡览动作,通常会利用NavigationService来做,例如
NavigationService.Navigate(newUri("/ThirdPage.xaml",
UriKind.Relative));
利用这个方式就可以巡览到下一个页面,那退回上一个页面呢?
这时候可以利用GoBack的方式来返回,例如
NavigationService.GoBack();
那如果不用GoBack的方式,直接也利用Navigate的方式指定页面名称呢?
当然也是可以巡览到指定的页面,但是要注意的是,利用Navigate方法时,是会产生一个『新』的目标页面的,这是两个方式不同的地方;举个简单的例子来说;假设在MainPage当中,摆放了一个TextBox,输入一些文字之后,巡览到SecondPage;这时候如果使用GoBack的方式(或是按下硬件的返回键),您会发现TextBox会记住刚刚输入的文字,而如果是用Navigate加上指定页面的方式,您会发现TextBox的文字会是默认的初始设定,而不会是刚刚输入的文字。
到这里,相信您对于页面以及应用程序的生命周期有大略的认识与了解,而在这些事件中,最常需要处理的就是去保存应用程序相关的状态;主要在Deactivated以及Activated这类事件中处理的是整个应用程序通用性的数据或是状态;而OnNavigateTo这类事件中则是处理页面使用的暂时数据或是处理其他传递过来的数据,接下来就来看一下,在各个页面中传递数据是用什么方式进行,以及如何去保存一些应用程序的状态。
在页面中传递数据
传递数据数据的方式有很多种,可以依照不同的状况去使用,下面笔者大致列出几种方式,您可以依照使用的情境以及需求做调整
利用全局变量的方式
自行宣告全局变量或是在App类别中(App.xaml.cs),去建立相关的属性(property)或是字段(flied)
例如说,笔者在App.xaml.cs中去新增一个字符串变量,大概像这个样子
publicstaticstringSharedString="";
之后在主要页面(mainpage)中,就可以利用下面的方式来储存要传递的数据
App.SharedString=textBox1.Text;
NavigationService.Navigate(newUri("/Page_UseApp.xaml",
UriKind.Relative));
而接着在新的页面中,就可以在OnNavigateTo的事件中去取值,并且把值显示出来,例如
protectedoverridevoidOnNavigatedTo(System.Windows.Navigation.NavigationEventArgse)
{
base.OnNavigatedTo(e);
textBox1.Text=App.SharedString;
}
笔者这边是利用简单的字符串变量来做示范,实际使用时您也可以用自定义类别或是其他的数据类型来使用,这就看您实际的需求;而在App类别中的相关数据是整个应用程序都可以共享的。
利用Url参数传递
利用像是SecondPage.xaml?
para1=12345¶2=aaaaa的方式来传递数据,这样的方式跟以往在开发Web应用程序的时候是极其类似的;例如说在主要页面中,笔者以下面的方式来呼叫Navigate方法
privatevoidbtnUseUrl_Click(objectsender,RoutedEventArgse)
{
NavigationService.Navigate(newUri("/Page_UseUrl.xaml?
msg="+textBox1.Text,UriKind.Relative));
}
而在目标页面中,就可以利用NavigationContext来取值,例如
protectedoverridevoidOnNavigatedTo(System.Windows.Navigation.NavigationEventArgse)
{
base.OnNavigatedTo(e);
textBox1.Text=NavigationContext.QueryString["msg"];
}
在小量的资料传递下,可以采用这种方式将资料传递到另一个页面中。
利用PhoneApplicationSerivce中的State属性
State是一个实做IDictionary的类别,可以用来保存应用程序的相关数据;使用时感觉跟全局变量的方式有点类似,因为它也是在整个应用程序中都可以去使用的;使用时要特别留意Key的命名,不能重复使用;而要使用时,必须要先引用Microsoft.Phone.Shell的命名空间,在mainpage的部分大概会利用像是下面这样的方式来做使用
privatevoidbtnUseState_Click(objectsender,RoutedEventArgse)
{
PhoneApplicationService.Current.State["msg"]=textBox1.Text;
NavigationService.Navigate(newUri("/Page_UseState.xaml",UriKind.Relative));
}
而在目标页面中,取值得方式大致会像这个样子
protectedoverridevoidOnNavigatedTo(System.Windows.Navigation.NavigationEventArgse)
{
base.OnNavigatedTo(e);
objectdata=null;
if(PhoneApplicationService.Current.State.TryGetValue("msg",outdata))
textBox1.Text=(string)data;
else
textBox1.Text="error";
}
TryGetValue是为了防止对应的Key值不存在而使用的,或是您也可以利用try…catch来做,这个地方要记得要加上适当的错误处理。
而像是先前在lifecycle中提到的部分,如果您是将值保存到State中,那么除非应用程序结束,不然在Deactivated、Activated事件中,您还是可以去存取到相关的数据。
利用Isolatedstorage
永久性的数据应该使用隔离储存区来储存,以便下次程序开启时能够继续的使用;还记得在前几集讨论过的隔离储存区使用吗?
记得要引入相关的命名空间,笔者下面举个简单的例子;
usingSystem.IO.IsolatedStorage;
usingSystem.IO;
在写入档案部分的程序代码大致会像下面这样子
privatevoidbtnUseStorage_Click(objectsender,RoutedEventArgse)
{
IsolatedStorageFileisofile=IsolatedStorageFile.GetUserStoreForApplication();
if(isofile.FileExists("/data.txt"))
isofile.DeleteFile("/data.txt");
StreamWritersw=newStreamWriter(isofile.CreateFile("/data.txt"),System.Text.Encoding.UTF8);
sw.WriteLine("Somedatafromisolatedstorage");
sw.Close();
sw.Dispose();
isofile.Dispose();
NavigationService.Navigate(newUri("/Page_UseStorage.xaml",UriKind.Relative));
}
而读取的部分,通常来说,使用隔离储存区时可能会放置较多的数据,所以笔者这边在读取时多建立一条线程来做读取的动作,并且延迟1500ms来模拟这样的效果,读取动作的程序代码大概会像这样子
namespaceNavigateDemo
{
publicpartialclassPage_UseStorage:
PhoneApplicationPage
{
ThreadReadthread=null;
publicPage_UseStorage()
{
InitializeComponent();
}
protectedoverridevoidOnNavigatedTo(System.Windows.Navigation.NavigationEventArgse)
{
base.OnNavigatedTo(e);
//將progessbar設定為可見,並且將資料顯示部分設定為隱藏
textBlock1.Visibility=System.Windows.Visibility.Collapsed;
textBox1.Visibility=System.Windows.Visibility.Collapsed;
progressBar1.Visibility=System.Windows.Visibility.Visible;
//啟動執行續作業
Readthread=newThread(ReadStorageFile);
Readthread.Start();
}
privatevoidReadCompleted(stringvalue)
{
progressBar1.Visibility=System.Windows.Visibility.Collapsed;
textBlock1.Visibility=System.Windows.Visibility.Visible;
textBox1.Visibility=System.Windows.Visibility.Visible;
textBox1.Text=value;
}
//資料讀取完畢時,更新UI使用的委派事件
delegatevoiddeReadCompleted(stringvalue);
privatevoidReadStorageFile()
{
Thread.Sleep(11500);
IsolatedStorageFileisofile=IsolatedStorageFile.GetUserStoreForApplication();
if(isofile.FileExists("/data.txt"))
{
StreamReadersr=newStreamReader(isofile.OpenFile("/data.txt",FileMode.Open),System.Text.Encoding.UTF8);
stringtmpString=sr.ReadLine();
sr.Close();
sr.Dispose();
this.Dispatcher.BeginInvoke(newdeReadCompleted(ReadCompleted),newobject[]{tmpString});
}
else
{
this.Dispatcher.BeginInvoke(newdeReadCompleted(ReadCompleted),newobject[]{"filenotfound.."});
}
isofile.Dispose();
}
}
}
这边在读取时,利用progessbar来显示正在读取中的状态,画面大致会像下面左图,而读取完毕时再将数据显示在画面上
Idledetection
最后我们来看Idledetection的部分;什么是Idledetection呢?
这功能就是在设定系统闲置相关的侦测;例如说,如果装置一段时间没有使用(操作)的话,那么首先系统会将屏幕变暗,以节省电源,而再经过一段时间之后,便会锁定装置,将屏幕整个关闭,而这时候就会进入了上面生命周期提到的Deactivated事件,之后应用程序也进入tombstoning的状态。
那么当应用程序是用于拨放音乐,当装置锁定的情形下,我们仍然希望应用程序可以继续运作;或者应用程序是利用装置上的sensor(例如accelerometer)来进行,在应用程序执行过程中,可能长时间都不会有使用触控屏幕的情形,但这时候不希望系统进入待机的状态,那么这时候就要设定Idledetection了。
在开始之前,要先提醒各位,在Idledetection的部分,MarketPlace递交应用程序时是有一些规定的,请一定要确认WindowsPhone7ApplicationCertificationRequirements中的相关规定,不然应用程序是不能够上架的。
您可以在文件中的6.3节『ApplicatinsRunningunderaLockedScreen』中找到相关的资料。
好,了解该注意的事项之后,首先来看看侦测闲置的模式;在WindowsPhone7中,Idledetection有两种
∙ApplicationIdleDetectinMode
∙UserIdleDetectionMode
我们先来看ApplicationIdleDetection的部分;ApplicationIdleDetection是应用程序闲置状态侦测,例如经过一段时间没有使用的话,装置会进入锁定,并且引发应用程序的Deactivated事件,随后应用程序进入tombstoning状态;ApplicationIdleDetectionMode便是设定装置进入锁定时,应用程序会不会进入tombstoning状态,如果设定为关闭,那么将不会引发应用程序的Deacticated事件,也不会将应用程序进入tombstoning;好处是甚么呢?
大约有下列几点
∙应用程序仍然在执行中
∙当用户返回应用程序时,由于没有进入tombstoning的状态,能够快速回复
而要注意的地方约略如下
∙应用程序仍然在执行,所以会继续的消耗电池的电力;请特别注意,装置同样会进