2017/3/1

Xamarin.Forms 教學系列文(六.貳)App Lifecycle & Properties


本篇沒有圖就是狂。


學習目標
  • Application.Current.Properties 不死系儲存值物件
  • App Lifecycle
  • App class 和 Page class 全域變數溝通

假設你在 六.壹 最後一個範例程式按下一長串重要的數字,卻來了一通電話導致 App 中斷 ( terminate ),當你結束通話後重新開啟 App,你還是會希望此串數字是 存在 的吧!

當然系統不會聰明到自動幫你存下這些資料,所以這一小節教你如何在 App 中斷時,手動存下資訊。


Two facilities

當 App 中斷時,該如何儲存畫面上的資訊或狀態,並於下次打開 App 時復原。 

Application class 利用以下兩個機制(Facilities),來幫忙完成這件事情:

  • Properties,Dictionary<string, object> 類別,用來儲存值。
  • OnStart, OnSleep, OnResume這些方法就是我們所知道的應用程式生命週期 (application lifecycle)。

要使用這些機制,首先你要確定 App 中斷時哪些資訊需要被儲存,一般來說會將使用者設定存下,例如 App 字體大小、顏色等... 或是使用者輸入到一半的資料,都可以在 Porperties 新增一組 key-value 存下。

但若使用者要儲存較大的檔案文件,就不建議用 Properties 了,必須直接將大型文件存在手機內 ( 20 章會提到 I/O )。



Properties

儲存值:
Application.Current.Properties["displayLabelText"] = displayLabel.Text;

不用擔心 key 值不存在於 Properties,若不存在會自動新增一組新的 key-value。

復原值:
IDictionary properties = Application.Current.Properties;

if(properties.ContainsKey("displayLabelText"))
{
 displayLabel.Text = properties["displayLabelText"] as string;
}

其實相當簡單,就是將值丟進 Properties,要用的時候再藉由 key 取出來,而這個 Application.Current.Properties 可以把他想成不死系的字典物件...


App Lifecycle

一般來說 Properties 會搭配 App lifecycle 一起使用,底下三個 function 可以在 App 看到:
public class App : Application 
{     
    public App()     
    {         
        …     
    } 
 
    protected override void OnStart()    
    {        
        // Handle when your app starts     
    } 
 
    protected override void OnSleep()     
    {         
        // Handle when your app sleeps     
    } 
 
    protected override void OnResume()     
    {         
        // Handle when your app resumes     
    } 
} 

最重要是 OnSleep 這方法,一般來說,當手機太久沒使用就會進入睡眠模式,一旦進入睡眠模式後,執行中的 App 就會被中斷並呼叫 OnSleep 方法。
若 App 是因為本身 crash 而關閉,就不會呼叫 OnSleep 方法。
測試 OnSleep 最簡單的方法就是當你在執行 App 時,按下 Home 或是 Back 鍵,就能將 App 中斷。

問題來了,通常要儲存的值會出現在一般的 Page 類別內,而 OnSleep 方法存在於 App 類別...Page 和 App 勢必要透過一些方法溝通,才能於 App 內的方法儲存 Page 的值

這裡提供一個方法,
可以先在 App 類別下宣告需要被儲存的變數 (全域):
    public class App : Application 
    {    
        public App()     
        {        
            …     
        } 
 
        public string DisplayLabelText { set; get; }
     
    }


在 OnSleep 時將此全域變數存入 Properties 內,而在 App 建構子時將 Properties 存下的值指派回全域變數:
namespace PersistentKeypad
{
    public class App : Application
    {
        const string displayLabelText = "displayLabelText";
        public App()
        {
            if (Properties.ContainsKey(displayLabelText))
            {
                DisplayLabelText = (string)Properties[displayLabelText];
            }
            
            MainPage = new PersistentKeypadPage();
        }
        public string DisplayLabelText { set; get; }
        protected override void OnStart()
        {
            // Handle when your app starts 
        }
        protected override void OnSleep()
        {
            // Handle when your app sleeps 
            Properties[displayLabelText] = DisplayLabelText;
        }
        protected override void OnResume()
        {
            // Handle when your app resumes 
        }
    }
}

上面範例為了避免拼字錯誤,所以先將 key 值用 displayLabelText 變數存下。


接著來看 Page 那一端:
public class PersistentKeypadPage : ContentPage 
{     
    Label displayLabel;     
    Button backspaceButton; 
 
    public PersistentKeypadPage()     
    { 
        //RESTORE
        // New code for loading previous keypad text.         
        App app = Application.Current as App;         
        displayLabel.Text = app.DisplayLabelText;         
    } 
 
 
    void OnButtonClicked(object sender, EventArgs args)     
    {         
        Button button = (Button)sender;         
        displayLabel.Text += (string)button.StyleId;       
 
        // Save keypad text.         
        App app = Application.Current as App;         
        app.DisplayLabelText = displayLabel.Text;     
    } 
}

可以看到程式 Page 內都是透過 app.DisplayLabelText 這全域變數在運作,

利用全域變數這樣簡單的溝通,就能達到我們 App 中斷時存下畫面上的資訊 這目的。




沒有留言:

張貼留言