精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

詳解Windows Phone開發中的墓碑機制

移動開發
墓碑機制是系統自動完成的,但是數據的保存和恢復則是我們通過代碼控制的。另外墓碑機制也不是萬能的,因為此時程序是終止的,如果有一些下載,播放,計時的功能就無法通過墓碑機制完成到了。

目前的智能手機,硬件上已經可以媲美幾年前的PC機了,1G內存,512M以上內存,3.5以上的屏幕,3G,WIFI等等都成為了新的手機的最低標準。而Windows Phone也一改以往WM手機硬件差異大的問題,設定了最低的硬件標準。相對于以前系統,性能上,操作上,流暢度上也有了很大提高。但是電池的發展遠遠跟不上手機的耗電量。大的也就1500MA的電池,最多也就使用1天多,大部分每天都用充電。為了節約電量,各個平臺的手機都推出了一些省電的措施。

對于Windows Phone來說,剛推出時和iPhone第一版一樣,不支持多任務,一方面是為了給前臺程序提供更多的資源,更流暢的體驗,另一方面也是為了介紹電池的消耗。同事采用了消息推送機制來完成一部分后臺操作,也使用了一種名為墓碑機制來對實現所謂的了“偽多任務”。 到了最新的“芒果”系統,已經支持了多任務,但也不同于以往WM說或PC上的多任務,也改進了墓碑機制,加快了程序間的切換。我們這一篇文章就了解下Windows Phone平臺的偽多任務。

一、偽多任務

在我們使用PC和WM系統時,多任務對我們來說是理所應當的。一邊聽歌,一邊上QQ,還能上微博發照片。可到了Windows Phone上卻不支持多任務了,對于一個新的智能系統來說,確實無法讓人接受。但是多任務存在一個問題就是如果開的任務過多,系統用起來就會比較卡,在WM系統中這種情況比較常見。為了提供用戶的體驗,目前的一些智能系統都放棄了這種傳統的多任務方式,而采用了偽多任務,有限制的多任務和消息推送這些方法。

所謂的偽多人他并不是真正的多任務,只是通過一些處理,讓用戶使用起來感覺不到和多任務有什么區別。在Windows Phone中采用了墓碑機制來實現偽多任務。墓碑這個名字也很恰當。當我們運行了一個程序后,切換到另一個程序,這時因為是單任務,第一個程序會被終止掉,但是采用墓碑機制,保存了程序當前的狀態和數據,當我們在切換回的時候,雖然是啟動了一個新的實例,但是可以通過墓碑來恢復到之前的狀態,所以用戶感覺不到有什么區別。

墓碑機制是系統自動完成的,但是數據的保存和恢復則是我們通過代碼控制的。另外墓碑機制也不是萬能的,因為此時程序是終止的,如果有一些下載,播放,計時的功能就無法通過墓碑機制完成到了。Windows Phone 7則通過推送機制來解決部分問題,而WP7.1 SDK中也提供了一些后臺操作來解決這些問題,這一篇文章我們主要介紹墓碑機制。

二、程序執行模型

在深入了解墓碑機制之前我們必須弄清楚程序的執行模型。下面這個圖就是Windows Phone 7.1中最新的執行模型。此圖來自于MSDN,但是他的圖有個錯誤,修改了下。

程序執行模型

對于一個Windows Phone程序來說,他有啟動---運行---休眠---墓碑---退出等5個狀態,狀態切換之間存在一些事件和方法。下面就具體介紹一個程序從啟動到終止的過程。

1.啟動一個程序

我們啟動一個程序有多種方法,最普遍的就是在第一屏界面點擊程序的Tile圖標或者是在第二屏中點擊程序圖標,另外我們可以通過點擊一個推送的Toast消息或者通過Launchers 和 Choosers來啟動程序,這些后面會介紹。在啟動程序是,會觸發Application的Launching事件。這個事件我們前面提到過,他是PhoneApplicationService類中注冊的事件,除此之外好包含了三個和程序狀態相關的事件。

程序啟動會會創建一個新的實例,為了保證程序能過正??焖俚膯?,我們不應該在Launching事件中執行過多的代碼,比如讀取文件,網絡連接等等,這樣會印象用戶體驗,我們可用另起一個線程來執行這些操作。

2.程序運行

程序啟動以后就進入了運行狀態,程序從啟動到進入第一個頁面的過程我們在前面討論頁面導航的文章中詳細介紹過了。通過從配置文件獲得要加載的第一個XAML頁面,讀取XAML文件并生成新的實例,通過Frame顯示出這個Page。我們知道在進入一個Page時會執行OnNavigatedTo方法。當這些完成后,程序才真正進入了運行狀態。而OnNavigatedTo方法對于墓碑機制來說非常重要,我們一般在這個方法中進行一些數據恢復的操作。

3.休眠狀態

這個狀態是在WP7.1中新加入的一個狀態,是為了提升多個任務間的切換速度。當我們在程序中點擊Win鍵進入到主界面,或者是在程序中使用了Launchers 和Choosers啟動了另一個程序時就會發生(不是所有都會發生)。休眠狀態時,程序停止運行,但是整個進程還是存在于內存中。當恢復這個程序時,就不需要創建一個新的實例。這樣就加快了程序恢復和切換的速度。而且從休眠狀態恢復時我們一不需要去恢復數據。而在WP7.1中,我們可以長按Back按鈕,出現程序列表,然后選擇要前臺執行的程序。

在切換到其他程序,進入到休眠狀態之前,會調用當前頁面的OnNavigatedFrom方法,在這個方法中我們可以保存當前頁面的一些數據狀態;然后會觸發Application中的Deactivated事件,在這個事件中,我們可以保存一些當前程序的數據。我們知道,因為進程資源還保存在內存中,所以當前臺程序使用時,內存不足或者不足以讓程序流暢運行,這時系統就會執行一些操作來釋放內存,此時程序就可能從休眠狀態變換為下面介紹的墓碑狀態。

4.墓碑狀態

如上面說的,在WP7.1中,只有系統資源不夠前臺程序使用時,后臺程序才可能從休眠狀態進入到墓碑狀態。這也是WP7.1相對于WP7.0最大的改進。在WP7.0中,系統沒有休眠狀態,仍和后臺程序都是直接進入到墓碑狀態,而OnNavigatedFrom方法和Deactivated事件都是在進入墓碑轉臺前觸發的。一個程序進入到墓碑狀態時,他的進程被終止掉,但是程序的回退棧中的信息,以及我們保存的一些信息會保留在內存中。

為了保證系統資源和性能,Windows Phone對墓碑狀態也做了一些限制。目前系統中之允許同時存在5個墓碑程序。當超過了這個數量或者因為前臺程序需要更多的資源,那么系統就會完全終止掉我們的程序,包括閃存內存中保存的回退棧和數據信息。所以對于我們而言,好需要對這種情況進行處理。

5.程序恢復

當我們使用Back按鈕或者長按Back從任務列表中返回程序,或者是從Launchers 或Choosers返回時,程序就會恢復執行。但是如圖上看到的,我們程序可能是從休眠狀態,也可能是從墓碑狀態返回的。如果是從休眠狀態返回時我們不需要做任何恢復的操作,而從墓碑程序中返回,我們就需要恢復程序的狀態和數據,以便用戶感覺程序是被重寫創建了。

程序恢復時會觸發Application類中的Activated事件,我們可以通過檢查IsApplicationInstancePreserved參數來判斷程序是從休眠狀態還是墓碑狀態返回的,在此方法中我們可以用來恢復之前在Deactivated事件中保存的數據。如果是從休眠狀態恢復,不會重新執行構造函數,而從墓碑狀態恢復時會重新執行構造函數。因為Back Stack在墓碑狀態中還是保存在內存中的,所以這是會返回到我們程序退出時所在的頁面,在進入到頁面之前還是會執行OnNavigatedTo方法,對于墓碑狀態恢復的程序,我們可以在這個方法中來恢當前頁面的狀態數據。

6.程序結束

在Windows Phone的silverlight框架程序中,我們唯一退出程序的方法就是點擊Back鍵,當Back Stack中不存在頁面時程序就會退出,目前系統沒有提供任何Exit方法來以代碼的方式結束程序。在程序退出時會觸發Application中最后一個事件,Closing。在這個事件中我們可以釋放一些使用的資源,保存數據等等,要注意的是,如果一個程序從墓碑狀態被結束,是不會觸發此事件的。MSDN上說關閉程序的時間被限制在10s,超過這個時間程序會被終止掉。

#p#

三、數據保存和恢復

至此,我們對于Windows Phone的執行模型也有了一定了解,即便WP7.1中引入了休眠方式,但是程序還是可能進入到墓碑模式或則被終止掉。所以無論什么情況,我們都要對數據進行保存和恢復。不過我們可以通過一些系統狀態來判斷是否需要進行數據保存和恢復。

在進入到墓碑狀態時,數據會被保存到內存中,系統為我們提供了數據字典來保存我們的數據。 對于程序來說,系統的狀態和數據我們可以存放到Application.State這個字典這種,而對于單個頁面來說數據可以存放到Page.State的字典中。需要注意的是這些字典中存入的數據必須是可序列化的數據。另外我們也可以把數據保存到隔離存儲區中。

有了數據保存的區域下面就是數據保存的時機,在Application相關的: Launching、Deactivated、Activated和Closing這4個事件中我們可以對系統的數據進行保存和恢復,而在每個頁面進入和離開都會發生的OnNavigatedTo和OnNavigatedFrom,我們可以用來保存和恢復頁面的數據。

1.單頁面的情況

單頁面的情況 單頁面的情況

我們看個列子,Demo5中我們新建了2個頁面。在MianPage中有一個TextBox和三個按鈕。點擊Add時,TextBox的值會增加(默認是1),而點擊Next按鈕會導航到Page1頁面,點擊Run Camera按鈕會調用相機。代碼運行環境是WP7.1 SDK Beta2。我們在Application的四個事件和頁面的2個方法中只加入運行的Log信息。

  1. public MainPage()    
  2.  
  3. {    
  4.  
  5.    Debug.WriteLine("MainPage Constructor");    
  6.    camera = new CameraCaptureTask();    
  7.    camera.Completed += new EventHandler<PhotoResult>(camera_Completed);    
  8.    num = 1;    
  9.    InitializeComponent();    
  10.    txtNum.DataContext = num;    
  11.  
  12. }    
  13.  
  14. private void Button_Click(object sender, RoutedEventArgs e)    
  15.  
  16. {    
  17.  
  18.    txtNum.DataContext = ++num;    
  19.    Debug.WriteLine("Add Method,TextBox is {0}", num.ToString());    
  20.  

我們點擊Add讓TextBox值增加。然后點擊Win鍵回到住界面,然后點擊Back返回程序,并繼續點Add,程序Log信息如下:

  1. Application_Launching    
  2. MainPage Constructor    
  3. MainPage OnNavigatedTo    
  4. Add Method,TextBox is 2    
  5. Add Method,TextBox is 3    
  6. Add Method,TextBox is 4    
  7. MainPage OnNavigatedFrom    
  8. Application_Deactivated    
  9. Application_Activated    
  10. MainPage OnNavigatedTo    
  11. Add Method,TextBox is 5    
  12. Add Method,TextBox is 6 

很明顯,因為在WP7.1下,程序進入了休眠狀態,所以我們TextBox不會被清空。讓我們在模擬器上來模仿一下墓碑狀態的情況,需要進行如下設置就可以了。

墓碑狀態

然后我們再次運行程序,結果如下:

  1. Application_Launching    
  2. MainPage Constructor    
  3. MainPage OnNavigatedTo    
  4. Add Method,TextBox is 2    
  5. Add Method,TextBox is 3    
  6. Add Method,TextBox is 4    
  7. MainPage OnNavigatedFrom    
  8. Application_Deactivated    
  9. The thread '<No Name>' (0xec600c2) has exited with code 0 (0x0).    
  10. The thread '<No Name>' (0xee100aa) has exited with code 0 (0x0).    
  11. The thread '<No Name>' (0xe6a00ae) has exited with code 0 (0x0).    
  12. 'UI Task' (Managed): Loaded 'C:\Program Files\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\mscorlib.dll'    
  13. 'UI Task' (Managed): Loaded 'System.Windows.RuntimeHost.dll'    
  14. 'UI Task' (Managed): Loaded 'System.dll'    
  15. 'UI Task' (Managed): Loaded 'System.Windows.dll'    
  16. 'UI Task' (Managed): Loaded 'System.Net.dll'    
  17. 'UI Task' (Managed): Loaded 'System.Core.dll'    
  18. 'UI Task' (Managed): Loaded 'System.Xml.dll'    
  19. 'UI Task' (Managed): Loaded '\Applications\Install\F5BE083B-4EC0-4192-84B0-EE83323B8240\Install\Demo5.dll', Symbols loaded.    
  20. 'UI Task' (Managed): Loaded 'Microsoft.Phone.dll'    
  21. 'UI Task' (Managed): Loaded 'Microsoft.Phone.Interop.dll'    
  22. 'UI Task' (Managed): Loaded 'System.Runtime.Serialization.dll'    
  23. Application_Activated    
  24. MainPage Constructor    
  25. MainPage OnNavigatedTo    
  26. Add Method,TextBox is 2    
  27. Add Method,TextBox is 3 

 

很明顯看到,在執行完Deactivated事件后程序的線程都結束了,而但我點擊Back按鈕后,重新加載了程序,并且執行了MainPage的構造函數,而我們TextBox的值也從1開始了。下面看看如何來保存這些數據。對代碼修改如下:

  1. protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)    
  2.  
  3. {    
  4.  
  5.     Debug.WriteLine("MainPage OnNavigatedFrom");    
  6.     base.OnNavigatedFrom(e);    
  7.     State["num"] = num; //保存變量    
  8.  
  9. }   
  10.  
  11. protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)    
  12.  
  13. {    
  14.  
  15.     Debug.WriteLine("MainPage OnNavigatedTo");    
  16.     base.OnNavigatedTo(e);    
  17.     num = (int)State["num"]; //恢復變量    
  18.  

 

我們在MainPage的兩個方法中保存和恢復數據,但是運行卻出錯了。因為OnNavigatedTo中的State["num"]為空。因為我們第一次進入頁面時也會執行這個方法,這時還沒有保存過num,所以就出錯了。在WP7.0中我們可以使用 State.ContainsKey或者State.TryGetValue來避免這種錯誤的發生,任何時候我們從字典中讀取數據時都必須檢查數據的有效性。而在WP7.1中我們有更好的辦法:

  1. protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)    
  2.  
  3. {    
  4.  
  5.     Debug.WriteLine("MainPage OnNavigatedFrom");    
  6.  
  7.     base.OnNavigatedFrom(e);    
  8.  
  9.     if (e.NavigationMode != System.Windows.Navigation.NavigationMode.Back)    
  10.  
  11.     {    
  12.  
  13.         Debug.WriteLine("Save data");    
  14.  
  15.         State["num"] = num; //保存變量    
  16.  
  17.       }    
  18.  
  19. }   
  20.  
  21. protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)    
  22.  
  23. {    
  24.  
  25.      Debug.WriteLine("MainPage OnNavigatedTo");    
  26.      base.OnNavigatedTo(e);    
  27.      if (e.NavigationMode != System.Windows.Navigation.NavigationMode.New)    
  28.      {    
  29.  
  30.          Debug.WriteLine("Recover data");    
  31.   object objNum;    
  32.   if (State.TryGetValue("num", out objNum))    
  33.   {    
  34.       num = (int)objNum;    
  35.   }   
  36.  
  37.      }    
  38.      txtNum.DataContext = num;    
  39.  

 

我們在看看結果:

  1. Application_Launching    
  2. MainPage Constructor    
  3. MainPage OnNavigatedTo    
  4. Add Method,TextBox is 2    
  5. Add Method,TextBox is 3    
  6. Add Method,TextBox is 4    
  7. MainPage OnNavigatedFrom    
  8. Save data    
  9. Application_Deactivated    
  10. The thread '<No Name>' (0xfa800f2) has exited with code 0 (0x0).    
  11. The thread '<No Name>' (0xf9500e6) has exited with code 0 (0x0).    
  12. The thread '<No Name>' (0xe3700ee) has exited with code 0 (0x0).    
  13. 'UI Task' (Managed): Loaded 'C:\Program Files\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\mscorlib.dll'    
  14. 'UI Task' (Managed): Loaded 'System.Windows.RuntimeHost.dll'    
  15. 'UI Task' (Managed): Loaded 'System.dll'    
  16. 'UI Task' (Managed): Loaded 'System.Windows.dll'    
  17. 'UI Task' (Managed): Loaded 'System.Net.dll'    
  18. 'UI Task' (Managed): Loaded 'System.Core.dll'    
  19. 'UI Task' (Managed): Loaded 'System.Xml.dll'    
  20. 'UI Task' (Managed): Loaded '\Applications\Install\F5BE083B-4EC0-4192-84B0-EE83323B8240\Install\Demo5.dll', Symbols loaded.    
  21. 'UI Task' (Managed): Loaded 'Microsoft.Phone.dll'    
  22. 'UI Task' (Managed): Loaded 'Microsoft.Phone.Interop.dll'    
  23. 'UI Task' (Managed): Loaded 'System.Runtime.Serialization.dll'    
  24. Application_Activated    
  25. MainPage Constructor    
  26. MainPage OnNavigatedTo    
  27. Recover data    
  28. Add Method,TextBox is 5    
  29. Add Method,TextBox is 6 

 

數據被正常恢復了,我們可以看到,OnNavigatedTo方法雖然被執行了兩次,但是Recover data只有在從墓碑或休眠狀態返回時才執行,而在新建時是沒有執行的。因為在WP7.1中開放了NavigationEventArgs 的NavigationMode屬性。當我們新建一個頁面進入時,此屬性為New,而當我們從墓碑狀態或其他頁面返回時則是Back,很明顯我們只有在Back時才需要恢復數據。而在OnNavigatedFrom方法中,當我們導航到新的頁面時,此屬性為New,而當我們回退到前一個頁面時,此屬性為Back,我們知道Windows Phone中只有Back Stack,所以從一個頁面返回到前一個頁面時,這個頁面就會被回收,所以就沒有必要保存數據了。而在WP7中我們每次都要進行保存和恢復操作。

但是這里還有一個問題,就是當我們從休眠狀態返回時,是不需要進行數據恢復的,但是此方法還是會被執行,在WP7.1中同樣提供了方法,可以在休眠狀態返回時不執行這些操作。我們在Application的Activated 事件中可以判斷,我們修App代碼如下:

  1. public static bool IsTombstoning { get; set; }    
  2. private void Application_Activated(object sender, ActivatedEventArgs e)    
  3.  
  4. {    
  5.  
  6.    Debug.WriteLine("Application_Activated");    
  7.    if (e.IsApplicationInstancePreserved)    
  8.    {    
  9.  
  10.        IsTombstoning = false;    
  11.  
  12.    }    
  13.    else    
  14.    {    
  15.  
  16.        IsTombstoning = true;    
  17.  
  18.    }    
  19.  

 

WP7.1中新增了IsApplicationInstancePreserved屬性來判斷是休眠狀態還是墓碑狀態恢復的。我們在App中定義了一個靜態的IsTombstoning屬性。在MainPage的OnNavigatedTo方法中使用就行了。有一點要注意的是不要在App的構造函數中對IsTombstoning 賦值,否則從墓碑狀態返回后會執行構造函數,另外也不要在頁面中定義一個變量來指示是否是新的實例,因為你需要保存或恢復這個變量。取消Debug中的墓碑調試,我們看看結果。

  1. Application_Launching    
  2. MainPage Constructor    
  3. MainPage OnNavigatedTo    
  4. Add Method,TextBox is 2    
  5. Add Method,TextBox is 3    
  6. Add Method,TextBox is 4    
  7. Add Method,TextBox is 5    
  8. Add Method,TextBox is 6    
  9. MainPage OnNavigatedFrom    
  10. Save data    
  11. Application_Deactivated    
  12. Application_Activated    
  13. MainPage OnNavigatedTo    
  14. Add Method,TextBox is 7 

 

2.多頁面的情況

前面已經了解了單頁面情況下的數據恢復,那么如果我們從主頁面切換到其他頁面,這時進入了休眠或墓碑狀態又會怎么樣呢?因為這是我們當前已經不是在MainPage頁面了。還是在Demo5中,我們點擊Add后,點擊Next按鈕,進入到Page1,然后點Win鍵,進入主菜單。在Page1中我們沒有進行數據存儲和恢復,我們只關心MainPage中的數據。我們就看看墓碑情況,運行結果如下:

  1. Application_Launching    
  2. MainPage Constructor    
  3. MainPage OnNavigatedTo    
  4. Add Method,TextBox is 2    
  5. Add Method,TextBox is 3    
  6. Main Pgee Navigate to Page1    
  7. Page1 Constructor    
  8. MainPage OnNavigatedFrom    
  9. Save data    
  10. Page1 OnNavigatedTo    
  11. Page1 OnNavigatedFrom    
  12. Application_Deactivated    
  13. The thread '<No Name>' (0xf88012a) has exited with code 0 (0x0).    
  14. The thread '<No Name>' (0xe220156) has exited with code 0 (0x0).    
  15. The thread '<No Name>' (0xf1d014a) has exited with code 0 (0x0).    
  16. 'UI Task' (Managed): Loaded 'C:\Program Files\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\mscorlib.dll'    
  17. 'UI Task' (Managed): Loaded 'System.Windows.RuntimeHost.dll'    
  18. 'UI Task' (Managed): Loaded 'System.dll'    
  19. 'UI Task' (Managed): Loaded 'System.Windows.dll'    
  20. 'UI Task' (Managed): Loaded 'System.Net.dll'    
  21. 'UI Task' (Managed): Loaded 'System.Core.dll'    
  22. 'UI Task' (Managed): Loaded 'System.Xml.dll'    
  23. 'UI Task' (Managed): Loaded '\Applications\Install\F5BE083B-4EC0-4192-84B0-EE83323B8240\Install\Demo5.dll', Symbols loaded.    
  24. 'UI Task' (Managed): Loaded 'Microsoft.Phone.dll'    
  25. 'UI Task' (Managed): Loaded 'Microsoft.Phone.Interop.dll'    
  26. 'UI Task' (Managed): Loaded 'System.Runtime.Serialization.dll'    
  27. Application_Activated    
  28. Page1 Constructor    
  29. Page1 OnNavigatedTo    
  30. Bace to MainPage    
  31. MainPage Constructor    
  32. Page1 OnNavigatedFrom    
  33. MainPage OnNavigatedTo    
  34. Recover data    
  35. Add Method,TextBox is 4 

 

事實證明,我們前面寫的代碼依舊有效,沒有進行任何修改就完成了任務。我們看到在導航到Page1之前就進行了數據保存。因為OnNavigatedFrom不僅在進入墓碑狀態前回執行,在離開當前頁面時也會執行。所以,即便是在Page1中進入了墓碑狀態,當我們返回程序,并返回到MainPage頁面是,還是會執行OnNavigatedTo方法來恢復數據,這時的頁面Mode也是Back。所以我們不需要為多頁面做特殊處理。

我們考慮下,如果從Page1頁面不是GoBack,而是使用Navigate方法重新導航到MainPage呢?這有什么關系,只不過是新建了一個頁面的實例,我們前一個MainPage還在Back Stack中。那么數據會恢復到這個MainPage中嗎,當然不會,我們使用的State屬性是每個頁面實例特有的。那我我如果想在每個新建的MainPage中都能繼續進行Add操作呢?

對于這種變態的需求,一般我是懶得做,肯定是你設計有問題,但是這里還是演示下如何實現。除了使用Page的State,前面我們還提到使用Application的State,這個是所有頁面共享的。我們在Page中增加一個New按鈕,然后修改MainPage的方法:

  1. protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)    
  2.  
  3. {    
  4.  
  5.     Debug.WriteLine("MainPage OnNavigatedFrom");    
  6.     base.OnNavigatedFrom(e);    
  7.     Debug.WriteLine("Save data");    
  8.     PhoneApplicationService.Current.State["num"] = num; //保存到全局    
  9.  
  10. }    
  11.  
  12. protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)    
  13.  
  14. {    
  15.  
  16.     Debug.WriteLine("MainPage OnNavigatedTo");    
  17.     base.OnNavigatedTo(e);    
  18.     Debug.WriteLine("Recover data");    
  19.     object objNum;    
  20.     if (PhoneApplicationService.Current.State.TryGetValue("num", out objNum))    
  21.     {    
  22.         num = (int)objNum;    
  23.  txtNum.DataContext = num;    
  24.     }    
  25.  

 

為了一個變量能在不同實例中同時起作用,并公用,我們修改了頁面的方法。這里保存和恢復數據時都不在判斷是否是New或Back,因為任何情況我們都要保存和恢復,以便在所有頁面中使用。另外我們可以使用隔離數據區來存儲和恢復。結果就是,無論我們在Page1頁面從墓碑返回后, New一個MainPage,還是Back,或者是先New然后在返回到前一個MainPage,結果都是在任何頁面都能對這個數據繼續的使用。

當然更好的辦法是在App中定義一個全局的變量,這樣我們不需要在Page的頁面中對這些數據進行保存和恢復,只需要在Appliation的事件中進行。這樣代碼會很簡潔。

  1. public static int Number { get; set; }    
  2. private void Application_Activated(object sender, ActivatedEventArgs e)    
  3. {    
  4.  
  5.    Debug.WriteLine("Application_Activated");    
  6.    if (e.IsApplicationInstancePreserved)    
  7.    {    
  8.  
  9.        IsTombstoning = false;    
  10.  
  11.    }    
  12.    else    
  13.    {    
  14.  
  15.        IsTombstoning = true;    
  16.        Number = (int)PhoneApplicationService.Current.State["number"];    
  17.    }    
  18.  
  19. }    
  20.  
  21. private void Application_Deactivated(object sender, DeactivatedEventArgs e)    
  22.  
  23. {    
  24.  
  25.      Debug.WriteLine("Application_Deactivated");    
  26.      PhoneApplicationService.Current.State["number"] = Number;    
  27.  

 

App中代碼修改如上,我們在Activated和Deactivated中進行數據恢復和保存,因為Activated必定是在Deactivated執行后執行,所以這里沒有判斷是否存在。但還是應該寫的嚴謹一些。下面是MainPage中的代碼:

  1. protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)    
  2. {    
  3.  
  4.     Debug.WriteLine("MainPage OnNavigatedFrom");    
  5.     base.OnNavigatedFrom(e);    
  6.     App.Number = num;    
  7.  
  8. }    
  9.  
  10. protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)    
  11. {    
  12.  
  13.     Debug.WriteLine("MainPage OnNavigatedTo");    
  14.     base.OnNavigatedTo(e);    
  15.     num = App.Number;    
  16.     txtNum.DataContext = num;    
  17.  

 

代碼是非常的簡單,如果不是為了掩飾保存和恢復,我們甚至可以直接對App.Number來操作。相比前一種方法,代碼簡潔了很多。結果這里就不貼了。

3.使用Chooser的情況

在程序中我們可以使用Launcher或者Chooser來運行系統提供的API功能,比如打電話,發短信,調用相機等等。具體的使用我們后面會介紹。一般使用這些API都會導致當期那程序變為后臺程序。所以也存在數據恢復的問題,但是對于Chooser來說,他會返回數據,而Lanucher不會返回數據,那么這個時候就存在一個新得到的數據和被保存的數據我們應該用哪一個的問題。

看下面的列子,我們調用相機,返回后得到圖片的大小,把大小填入TextBox。

  1. private CameraCaptureTask camera;   
  2.  
  3. public MainPage()    
  4. {    
  5.    num = 1;    
  6.    camera = new CameraCaptureTask();    
  7.    camera.Completed += new EventHandler<PhotoResult>(camera_Completed);    
  8.    InitializeComponent();    
  9.    txtNum.DataContext = num;    

 

我們先定義相機的Chooser,注意這里要定義成類變量,而不能是局部變量,并且設置完成事件的處理方法。因為如果是局部變量,當系統進入到墓碑狀態在返回時,這個對象就沒有了,就沒辦法執行完成事件了,對于Chooser來說也沒有辦法獲得得到返回的數據了。

  1. private void Button_Click_2(object sender, RoutedEventArgs e)    
  2. {    
  3.  
  4.     Debug.WriteLine("Run Camera");    
  5.     try    
  6.     {    
  7.  
  8.        camera.Show();    
  9.  
  10.     }    
  11.     catch (System.InvalidOperationException ex)    
  12.     {    
  13.  
  14.        MessageBox.Show(ex.Message);    
  15.  
  16.     }    
  17. }    
  18.  
  19. void camera_Completed(object sender, PhotoResult e)    
  20. {    
  21.  
  22.     if (e.TaskResult == TaskResult.OK)    
  23.     {    
  24.  
  25.         BitmapImage bmp = new BitmapImage();    
  26.  bmp.SetSource(e.ChosenPhoto);    
  27.  num = bmp.PixelHeight;    
  28.  
  29.     }    
  30.     else    
  31.     {    
  32.  
  33.          num = 1024; //模擬器沒法拍照    
  34.  
  35.      }    

 

以上我們點擊Run Camera按鈕時,就調用Show方法調出,拍完照片后吧照片的高度設置到TextBox,因為模擬器拍不了,就手動設置到1024。頁面的數據我們采用第一種,單頁面的保存方式。

  1. Application_Launching    
  2. MainPage Constructor    
  3. MainPage OnNavigatedTo    
  4. Add Method,TextBox is 2    
  5. Add Method,TextBox is 3    
  6. Run Camera    
  7. MainPage OnNavigatedFrom    
  8. Save data    
  9. Application_Deactivated    
  10. Application_Activated    
  11. Set carmera num    
  12. MainPage OnNavigatedTo    
  13. Add Method,TextBox is 1025 

 

從上面結果可見程序調用相機時進入休眠狀態 ,返回后先執行了完成函數,Set carmera num后數據變成了1024。因為是休眠不需要恢復狀態,所以在此加1后變為1025。我們在看看從墓碑狀態返回的結果。

  1. Application_Launching    
  2. MainPage Constructor    
  3. MainPage OnNavigatedTo    
  4. Add Method,TextBox is 2    
  5. Add Method,TextBox is 3    
  6. Run Camera    
  7. MainPage OnNavigatedFrom    
  8. Save data    
  9. Application_Deactivated    
  10. The thread '<No Name>' (0xf3802a2) has exited with code 0 (0x0).    
  11. The thread '<No Name>' (0xe0a02da) has exited with code 0 (0x0).    
  12. The thread '<No Name>' (0xea002da) has exited with code 0 (0x0).    
  13. 'UI Task' (Managed): Loaded 'C:\Program Files\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\mscorlib.dll'    
  14. 'UI Task' (Managed): Loaded 'System.Windows.RuntimeHost.dll'    
  15. 'UI Task' (Managed): Loaded 'System.dll'    
  16. 'UI Task' (Managed): Loaded 'System.Windows.dll'    
  17. 'UI Task' (Managed): Loaded 'System.Net.dll'    
  18. 'UI Task' (Managed): Loaded 'System.Core.dll'    
  19. 'UI Task' (Managed): Loaded 'System.Xml.dll'    
  20. 'UI Task' (Managed): Loaded '\Applications\Install\F5BE083B-4EC0-4192-84B0-EE83323B8240\Install\Demo5.dll', Symbols loaded.    
  21. 'UI Task' (Managed): Loaded 'Microsoft.Phone.dll'    
  22. 'UI Task' (Managed): Loaded 'Microsoft.Phone.Interop.dll'    
  23. 'UI Task' (Managed): Loaded 'System.Runtime.Serialization.dll'    
  24. Application_Activated    
  25. MainPage Constructor    
  26. Set carmera num    
  27. MainPage OnNavigatedTo    
  28. Recover data    
  29. Add Method,TextBox is 4 

 

我們發現從墓碑狀態返回后,雖然也進行了Set carmera num,但是還進行了Recover data,最新得到數據被之前恢復的數據覆蓋了。我們看到返回后先執行了頁面的構造函數,然后執行了相機的完成方法,這里要注意的是,不要在這里操作控件,因為此時Load事件還沒有執行,這里操作控件會拋出一個空引用異常。

獲得的數據和保存的數據間的選擇是比較容易碰到的問題。我們要根據自己的邏輯來選擇解決的方法,這里我們使用最新的數據來代替保存的數據。所以修改恢復數據的部分:

  1. protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)    
  2. {    
  3.  
  4.    Debug.WriteLine("MainPage OnNavigatedTo");    
  5.    base.OnNavigatedTo(e);    
  6.    //單頁面情況    
  7.       if (App.IsTombstoning)    
  8.       {    
  9.  
  10.        if (e.NavigationMode != System.Windows.Navigation.NavigationMode.New)    
  11.        {    
  12.  
  13.           if (num == 1)    
  14.    {    
  15.  
  16.             Debug.WriteLine("Recover data");    
  17.      object objNum;    
  18.      if (State.TryGetValue("num", out objNum))    
  19.      {    
  20.  
  21.                num = (int)objNum;    
  22.  
  23.             }    
  24.  
  25.           }    
  26.  
  27.        }    
  28.  
  29.     }    
  30.  
  31.     txtNum.DataContext = num;    

 

我們知道如果進入到墓碑狀態返回后,num的數據會丟失,而我們在構造函數中把num設置為1。因為在調用OnNavigatedTo之前會執行方法相機的返回方法camera_Completed。如果num被設置為1024就不應該恢復數據。所以我們可以在OnNavigatedTo中通過num的值來判斷是否恢復,如果是1就需要恢復,如果不是就說明有新的值。

這里需要注意,如果在 camera_Completed中得到的數據就是1,那么還是會被恢復,所以一定根據情況來。這里只是舉例子。另外我們要注意構造函數中num初始化和camera.Completed事件綁定之間的順序,一定要先初始化數據,最后在注冊完成事件,否則執行完camera_Completed方法后,num又被初始化了。

下面看看執行結果:

  1. <strong>Application_Launching    
  2. MainPage Constructor    
  3. MainPage OnNavigatedTo    
  4. Add Method,TextBox is 2    
  5. Add Method,TextBox is 3    
  6. Run Camera    
  7. MainPage OnNavigatedFrom    
  8. Save data    
  9. Application_Deactivated    
  10. The thread '<No Name>' (0xe83037a) has exited with code 0 (0x0).    
  11. The thread '<No Name>' (0xeb50372) has exited with code 0 (0x0).    
  12. The thread '<No Name>' (0xf53033a) has exited with code 0 (0x0).    
  13. 'UI Task' (Managed): Loaded 'C:\Program Files\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\mscorlib.dll'    
  14. 'UI Task' (Managed): Loaded 'System.Windows.RuntimeHost.dll'    
  15. 'UI Task' (Managed): Loaded 'System.dll'    
  16. 'UI Task' (Managed): Loaded 'System.Windows.dll'    
  17. 'UI Task' (Managed): Loaded 'System.Net.dll'    
  18. 'UI Task' (Managed): Loaded 'System.Core.dll'    
  19. 'UI Task' (Managed): Loaded 'System.Xml.dll'    
  20. 'UI Task' (Managed): Loaded '\Applications\Install\F5BE083B-4EC0-4192-84B0-EE83323B8240\Install\Demo5.dll', Symbols loaded.    
  21. 'UI Task' (Managed): Loaded 'Microsoft.Phone.dll'    
  22. 'UI Task' (Managed): Loaded 'Microsoft.Phone.Interop.dll'    
  23. 'UI Task' (Managed): Loaded 'System.Runtime.Serialization.dll'    
  24. Application_Activated    
  25. MainPage Constructor    
  26. Set carmera num    
  27. MainPage OnNavigatedTo    
  28. Add Method,TextBox is 1025    
  29. </strong> 

 

和之前的區別就在于這里沒有恢復數據,最后使用的是相機得到的數據。對于沒有調用相機,而是點擊Win導致的程序恢復,這時恢復的數據,結果正確:

  1. Application_Launching    
  2. MainPage Constructor    
  3. MainPage OnNavigatedTo    
  4. Add Method,TextBox is 2    
  5. Add Method,TextBox is 3    
  6. MainPage OnNavigatedFrom    
  7. Save data    
  8. Application_Deactivated    
  9. The thread '<No Name>' (0xebe0382) has exited with code 0 (0x0).    
  10. The thread '<No Name>' (0xeb203be) has exited with code 0 (0x0).    
  11. The thread '<No Name>' (0xec103d6) has exited with code 0 (0x0).    
  12. 'UI Task' (Managed): Loaded 'C:\Program Files\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\mscorlib.dll'    
  13. 'UI Task' (Managed): Loaded 'System.Windows.RuntimeHost.dll'    
  14. 'UI Task' (Managed): Loaded 'System.dll'    
  15. 'UI Task' (Managed): Loaded 'System.Windows.dll'    
  16. 'UI Task' (Managed): Loaded 'System.Net.dll'    
  17. 'UI Task' (Managed): Loaded 'System.Core.dll'    
  18. 'UI Task' (Managed): Loaded 'System.Xml.dll'    
  19. 'UI Task' (Managed): Loaded '\Applications\Install\F5BE083B-4EC0-4192-84B0-EE83323B8240\Install\Demo5.dll', Symbols loaded.    
  20. 'UI Task' (Managed): Loaded 'Microsoft.Phone.dll'    
  21. 'UI Task' (Managed): Loaded 'Microsoft.Phone.Interop.dll'    
  22. 'UI Task' (Managed): Loaded 'System.Runtime.Serialization.dll'    
  23. Application_Activated    
  24. MainPage Constructor    
  25. MainPage OnNavigatedTo    
  26. Recover data    
  27. Add Method,TextBox is 4 

 

#p#

四、禁用墓碑

如果你擁有一臺真機,在升級到到芒果之前,或許總是要忍受恢復程序時的"Resuming"的提示。當然也不是沒有辦法,網上就流傳了修改注冊表來禁用墓碑狀態的方法。首先你需要有一臺已經越獄的機器,然后下載一個RegistryEditor的XPA軟件包。運行這個軟件,把\HKLM\Software\Microsoft\TaskHost\DehydrateOnPause的鍵值從3修改為0。再試試,程序切換的很快了,"Resuming"基本也不出現了。我買手機的時候Mango的Beta版已經出了,而且注冊表也已經被賣家修改好了。所以在手機上還沒見到"Resuming"就升級到Mango了。在我升級到7712之后,偶爾卻會出現"Resuming",所以決定研究下修改這個注冊表的作用。

搜索了好久,終于找到了一篇相關的文章:Tombstoning, Dehydration, and Windows Phone 。從文章中我們可以了解到,這個鍵值有4個選項:

1、Don’t dehydrate;

2、Forcefully dehydrate;

3、Gracefully dehydrate;

4、Automatically decide。

表示程序在暫停時是否執行Dehydrate,Dehydrate愿意是脫水。在進入墓碑狀態后,一些系統級別的操作會停止,運行環境開始回收資源,其中就包括.NET運行時,回收完以后整個程序的運行環境也被回收了。這樣一個過程就叫做Dehydrate。

系統默認是3,表示命令程序的運行環境在合適的時候優雅的執行Dehydrate。但是目前并不清楚是如何決定是否合適。但是對運行環境來說默認是執行Dehydrate,但是也可以選擇不進行Dehydrate。

HRESULT SHSetAutoDehydratingHostEligibility(BOOL fEligible); 

通過這個方法可以設置程序運行環境是否進行Dehydrate。當我們選擇2時,系統總是會執行Dehydrate,而選擇1時,系統會給程序發送一個WM_CLOSE消息來強制,理論上來說我們可以捕獲這個消息,來自己決定是否執行Dehydrate。而當設置為0是,Dehydrate被禁用了,也就是我們程序的運行環境不會被回收,.NET運行時,程序的實例都不會被銷毀。而在我們恢復程序是,主要是創建新的實例和.NET運行時,導致了出現"Resuming"。

所以我們修改注冊表為0后,系統看起來就系象7.1中的休眠狀態一樣了。而且程序恢復也不會創建新的實例,所以并不清楚和WP7.1的休眠有什么區別。也有可能7.1的休眠也是采用這種方式,默認不執行Dehydrate,而在資源不足時執行Dehydrate進入墓碑。這樣在恢復時會有Resuming字樣,而在WP7.0中不執行Dehydrate,當資源不夠時程序會被結束,所以不會出現Resuming字樣。這是我個人的猜測。在Mango中用不了注冊表工具,沒法查看。也不知道此鍵值是否還效或者是否有修改。

另外系統規定只能有5個程序進入墓碑狀態,我在真機上看了下,最多也只能有5個第三方的程序運行,而不管是休眠還是墓碑狀態。當你開第六個程序時,最早使用的程序就會被關閉,大家可以長按Back按鈕來觀察。

五、總結

通過上面介紹我們發現對于我們程序而言,墓碑機制中對數據的保存和恢復是我們需要關注的地方。我們通過三種情況,介紹了對頁面已經程序數據的保存和恢復方法,以及決定是否恢復數據的一般方法。了解了程序的執行模型。其中Page中的OnNavigatedTo和OnNavigatedFrom是最重要的方法。另外所有保存的數據必須可以被序列化。

下面是微軟關于執行模型的最佳時間方法:http://msdn.microsoft.com/zh-cn/library/ff817009.aspx

其中介紹了一些文章中沒有涉及的部分,比如當程序從墓碑模式被終止的時候需要保存數據到隔離區。所以我們應該在Deactivated事件中就進行這樣的操作,因為我們無法預料程序可能進入的狀態。另外有一點要指出,當我們程序被切換至后臺,進入到休眠或墓碑狀態時,此時我們點擊程序圖標,重新啟動一個實例時,之前的實例的數據都無法恢復。想解決這個問題只能把數據存放到隔離區,然后恢復。但是會出現歡迎界面,對于有登陸界面的的還會出現登陸界面,我們需要進行更多的處理,才能讓用戶感覺不到是新開的程序。另外其中還建議Application中的事件以及頁面中的兩個方法操作的時間不要超過10s,否則程序會被終止。但是我嘗試了下使用Thread.Sleep(15000),程序并沒有被終止。

責任編輯:王曉東 來源: cnblogs
相關推薦

2013-07-31 13:03:51

Windows PhoWindows Pho

2012-07-31 09:44:27

Windows Pho

2012-06-01 15:39:46

休眠狀態墓碑狀態

2012-02-02 16:37:51

Silverlight常用控件

2012-05-08 13:54:40

ToastPrompt

2014-12-22 14:21:57

Windows Pho隔離式存儲機制

2010-04-08 17:40:23

Windows Pho

2010-05-11 16:47:32

Windows Pho

2010-05-21 16:24:05

Windows Pho

2013-07-30 10:44:31

Windows PhoWindows Pho

2010-06-09 16:13:23

Windows Pho

2013-07-30 12:37:56

Windows PhoWindows Pho

2010-04-21 17:07:54

Windows Pho

2010-06-11 16:01:26

Windows Pho

2010-05-08 16:36:16

Windows Pho

2010-09-08 11:26:26

Windows PhoXNA 4.0 3D游戲開發

2011-06-07 12:42:15

Windows Pho

2013-04-17 14:00:06

Windows PhoWindows Pho

2013-04-16 17:02:50

Windows Pho概論

2013-04-19 16:34:56

Windows PhoWindows Pho
點贊
收藏

51CTO技術棧公眾號

91久色porny| 国产深夜精品| 亚洲第一精品福利| 免费无码av片在线观看| 男人的天堂在线视频免费观看 | 欧美综合精品| 欧美一a一片一级一片| 影音先锋成人资源网站| 深夜福利在线视频| 国产一区二区视频在线| 欧美中文字幕在线| 校园春色 亚洲| 国产aⅴ精品一区二区三区久久| 欧美理论片在线| 国产免费黄视频| 怡红院在线播放| 国产天堂亚洲国产碰碰| 国产精品高清一区二区三区| 伊人久久国产精品| 亚洲一区激情| 美日韩精品免费观看视频| 91成年人网站| 91精品啪在线观看国产爱臀| 欧美视频一区二区三区在线观看| av免费看网址| 国产黄大片在线观看画质优化| 久久夜色精品一区| 国产精品乱子乱xxxx| 在线观看av大片| 久久久精品五月天| 97av在线播放| 精品无码av在线| 亚洲精品va| 中文字幕亚洲欧美在线 | 麻豆成人入口| 日韩三级高清在线| av中文字幕网址| 日本在线中文字幕一区二区三区 | 久久九九免费视频| 亚洲色图欧美色| 国产一区二区三区探花| 日韩精品免费在线视频| 艳妇乳肉亭妇荡乳av| 亚洲一级大片| 日韩精品专区在线| 亚洲一区二区图片| 欧美午夜在线播放| 欧美一区午夜精品| 韩国一区二区在线播放| 青草综合视频| 欧美日韩电影在线| 777一区二区| 日韩亚洲国产免费| 欧美美女一区二区在线观看| 日韩va在线观看| 二区三区精品| 日韩欧美一级二级三级久久久| 亚洲 国产 图片| 91麻豆精品| 日韩欧美你懂的| 精品国产aⅴ一区二区三区东京热| 国产精区一区二区| 欧美不卡一区二区三区四区| 国产综合内射日韩久| 欧美日韩一区二区三区在线电影| 亚洲精品久久7777777| 手机在线看片日韩| 国产精品自拍区| 中文字幕精品在线| 乱h高h女3p含苞待放| 中出一区二区| 97超碰国产精品女人人人爽| 一级片中文字幕| 日韩精品欧美精品| 国产日韩在线免费| 性一交一乱一乱一视频| 成人不卡免费av| 免费一区二区三区在在线视频| 精品美女视频在线观看免费软件| 国产欧美一区二区精品仙草咪| 自拍另类欧美| av漫画网站在线观看| 在线视频欧美精品| 超碰91在线播放| 日韩电影不卡一区| 少妇高潮久久77777| 久草资源在线视频| 亚洲在线黄色| 亚洲伊人久久综合| 亚洲欧洲国产综合| 国产精品不卡一区二区三区| 亚洲国产一二三精品无码| 超级碰碰久久| 欧美一区二区三区日韩视频| 中文字幕精品视频在线| 日韩精品免费一区二区在线观看| 欧美激情图片区| 日韩熟女一区二区| 国产黄色成人av| 欧美精品二区三区四区免费看视频 | 动漫精品一区一码二码三码四码| 久久综合伊人| 97人人模人人爽人人少妇| 国产最新视频在线观看| 一区二区三区欧美日韩| 毛葺葺老太做受视频| av不卡一区二区| 中文字幕久热精品在线视频| 国产无码精品一区二区| 久久精品国产99| 久久综合伊人77777麻豆| 国产原厂视频在线观看| 日本道精品一区二区三区| 伊人av在线播放| 日韩综合网站| 国产99在线|中文| 人妻一区二区三区四区| 亚洲日本电影在线| 午夜宅男在线视频| 思热99re视热频这里只精品| 欧美激情在线观看视频| 国产又粗又猛又爽又黄的视频一| 久久你懂得1024| 日本午夜激情视频| 久久久久久久久成人| 色婷婷综合成人av| 久久亚洲精品石原莉奈| 99久久婷婷国产综合精品电影| 成年丰满熟妇午夜免费视频| 欧洲午夜精品| 日韩中文字幕第一页| 久久久久亚洲视频| 久久精品亚洲麻豆av一区二区 | 岛国片av在线| 欧美一二三四区在线| 日本黄色免费片| 日本女优在线视频一区二区| 欧美凹凸一区二区三区视频| 天堂中文在线播放| 亚洲精品一区中文| 九九热在线免费观看| 不卡免费追剧大全电视剧网站| 波多野结衣与黑人| 亚洲综合影院| 欧美成人在线网站| 不卡视频免费在线观看| 亚洲女与黑人做爰| 午夜诱惑痒痒网| 亚洲蜜桃视频| 成人午夜影院在线观看| 日本在线观看高清完整版| 日韩欧美国产一区在线观看| 青草影院在线观看| 国产aⅴ综合色| 黄色一级视频在线播放| 噜噜噜天天躁狠狠躁夜夜精品| 97视频免费看| 亚洲av片在线观看| 日韩欧美在线视频观看| 免费观看av网站| 日本欧美久久久久免费播放网| 欧洲一区二区日韩在线视频观看免费| av亚洲一区二区三区| 自拍偷拍免费精品| 国内老熟妇对白hdxxxx| 亚洲大片精品永久免费| 日本少妇色视频| 日韩激情中文字幕| 中文字幕色一区二区| 日韩区一区二| 98精品在线视频| 国产女人在线视频| 91精品国产综合久久精品app| 玖玖爱免费视频| 91在线免费播放| 国产aaaaa毛片| 91精品蜜臀一区二区三区在线| 亚洲一区二区三区香蕉| bl视频在线免费观看| 亚洲欧洲午夜一线一品| 国产又粗又猛又爽| 精品久久久久久久久中文字幕| 欧洲美一区二区三区亚洲| 六月婷婷色综合| 国产精品国三级国产av| 国产精品一区二区av交换| 91网站免费观看| 成人性生交大片免费网站 | 日本裸体美女视频| 国产99久久久国产精品潘金网站| 欧美一级在线看| 亚洲高清影视| 精品久久久久久中文字幕动漫 | 国产精品9999久久久久仙踪林 | 亚洲aaaaaa| 国产精品专区免费| 美女福利视频一区| 国外av在线| 日韩精品一区二区三区在线播放 | 岛国毛片av在线| 最好看的2019的中文字幕视频| 亚洲av无码片一区二区三区| 91九色最新地址| 国产主播在线播放| 国产精品国产精品国产专区不蜜| 免费无码一区二区三区| 国产一区久久久| 另类小说第一页| 日韩午夜av在线| 国产高潮呻吟久久久| 国产videos久久| 国产另类自拍| 精品久久亚洲| 成人福利免费观看| 欧美中文字幕精在线不卡| 国内精品久久久久| 黄色免费在线观看网站| 永久555www成人免费| 熟妇高潮一区二区高潮| 精品久久久久一区| 国产三级三级在线观看| 欧美三级在线视频| 免费看日批视频| 偷拍一区二区三区| 日韩成人一区二区三区| 亚洲精品国产精华液| 免费黄色国产视频| 国产精品天干天干在线综合| 国产男男chinese网站| av不卡在线观看| 久久久久久久久久影视| 国产福利一区在线| 国产精品久久久久野外| 国产综合久久久久久鬼色 | 国产亚洲欧美日韩高清| 欧美三级欧美成人高清www| 国产成人啪精品午夜在线观看| 一区二区三区小说| 欧美成欧美va| 亚洲欧美另类在线| 一区二区三区影视| 亚洲精品自拍动漫在线| 夫妻性生活毛片| 亚洲色图欧美偷拍| 在线免费看av网站| 一区二区三区波多野结衣在线观看| 成人做爰视频网站| 最新久久zyz资源站| 精品国产大片大片大片| 亚洲同性同志一二三专区| xxxx日本少妇| 亚洲综合图片区| 国产成人精品a视频一区| 欧美日韩综合视频| 91黑人精品一区二区三区| 欧美午夜影院一区| 97人人爽人人爽人人爽| 欧美日韩一级片在线观看| 亚洲天堂网在线观看视频| 欧美高清视频www夜色资源网| 国产精品久久久久久免费免熟| 91精品一区二区三区久久久久久| 国产视频一二三四区| 精品欧美一区二区三区精品久久| 可以免费观看的毛片| 精品亚洲永久免费精品| 超碰在线国产| 久久精品视频网站| 国产丝袜在线观看视频| 青青久久aⅴ北条麻妃| 国产成人毛片| 成人影片在线播放| 亚洲瘦老头同性70tv| 亚洲精品成人a8198a| 伊人久久大香线蕉综合四虎小说| 美女扒开大腿让男人桶| 久久精品系列| 免费在线观看污网站| 不卡av在线免费观看| 精品人妻一区二区三区蜜桃视频| 亚洲欧美影音先锋| 国产 日韩 欧美 在线| 在线播放一区二区三区| 国产成人三级在线观看视频| 精品亚洲一区二区三区四区五区| 亚洲乱亚洲乱妇| 国内精品视频一区| 欧美va在线| 成人免费视频网站入口| 精品色999| 被灌满精子的波多野结衣| 日韩高清不卡一区二区三区| 国产调教打屁股xxxx网站| 国产色产综合色产在线视频| 青青草手机在线视频| 色www精品视频在线观看| 国产黄色片网站| 国产一区二区三区中文| 色黄网站在线观看| 国产成人免费91av在线| youjizzjizz亚洲| 深田咏美在线x99av| 亚洲欧洲视频| 日韩a一级欧美一级| 久久久国产精品不卡| 男女羞羞免费视频| 欧美日韩国产片| 欧美大片aaa| 久久久久国产精品免费| 精品亚洲a∨| 欧美日韩精品免费看| 狠色狠色综合久久| 久久6免费视频| 国产欧美日韩卡一| 国产一级免费视频| 亚洲国产精品人久久电影| 久草免费在线| 国产精品人成电影在线观看| 欧美电影完整版在线观看| 精品嫩模一区二区三区| 麻豆精品在线看| 黄色片网站免费| 色综合久久综合网欧美综合网| 国产小视频免费观看| 欧美成人精品一区| 999精品嫩草久久久久久99| 色999五月色| 日日摸夜夜添夜夜添国产精品| 在线精品一区二区三区| 亚洲成av人在线观看| 亚洲大尺度网站| 欧美国产日韩一区二区| 日韩三级精品| 高清无码一区二区在线观看吞精| 九九国产精品视频| 韩国一级黄色录像| 欧美日韩国产免费一区二区 | 国外成人在线播放| 国产suv精品一区二区四区视频| 欧美日韩激情四射| 国产成人超碰人人澡人人澡| 久久国产在线视频| 日韩欧美亚洲一区二区| 日本无删减在线| 91精品国产一区二区三区动漫| 一区二区三区四区在线观看国产日韩| 91小视频在线播放| 亚洲精品免费一二三区| 精品女同一区二区三区| 欧美激情免费看| 国产精品自在| 欧美亚洲一二三区| 久久久精品影视| 国模私拍一区二区| 色噜噜狠狠狠综合曰曰曰| 国产一区二区| 成人免费视频91| 久久综合五月天婷婷伊人| 91porny九色| 日韩中文娱乐网| 日韩成人18| 亚洲 欧美 日韩 国产综合 在线| 99久久免费视频.com| 樱花视频在线免费观看| 中文字幕亚洲无线码在线一区| 日韩大陆av| 狠狠精品干练久久久无码中文字幕| 国产91精品一区二区麻豆亚洲| 久久草视频在线| 一区二区欧美在线| 亚洲综合网站| 日韩av资源在线| 最近日韩中文字幕| 日韩一级中文字幕| 国产成人精品日本亚洲| 亚洲最大黄网| 国产精品一级黄片| 欧洲av一区二区嗯嗯嗯啊| av大大超碰在线| 免费不卡亚洲欧美| 久久精品99久久久| 男人的天堂一区| 日韩中文字幕免费| 欧美日韩看看2015永久免费 | 自拍偷拍18p| 九九视频这里只有精品| 亚洲国产欧美日韩在线观看第一区| 三级视频中文字幕| 亚洲电影第三页| 91大神在线网站| 国产乱码精品一区二区三区不卡| 免费在线看一区| 国产无遮挡又黄又爽又色| 中文字幕免费精品一区高清| 9l视频自拍蝌蚪9l视频成人| 在线视频日韩一区| 亚洲国产cao| 国产在线一区二区视频| 免费中文日韩| 成人视屏免费看|