Każdy zna taką sytuację. Wprowadzamy jakieś dane do aplikacji na naszym smartfonie. Powiedzmy, że piszemy smsa. W trakcie chcemy sprawdzić w kalendarzu datę spotkania. Przechodzimy więc do kalendarza, sprawdzamy, wracamy do aplikacji wiadomości. I wprowadzony poprzednio tekst smsa dalej tam jest. Jak gdyby nigdy nic. Jest to naturalne, że takie dane zostają. Jednak przy tworzeniu aplikacji, trzeba się nad tym bardziej pochylić.
Żadna z platform nie zapisuje za programistę takich danych. W zasadzie jest to zrozumiałe, bo nie wiadomo co, kiedy i gdzie miałoby zostać zapisane. To wie programista, więc jemu pozostawiono obsługę tego typu wydarzeń.
Nie ma problemu, gdy do czynienia mamy z jednym polem, tak jak w aplikacji do smsów.
Jednak w Codzienniku do zapisania mam kilka takich pól wprowadzania. Wypadek minimalizacji aplikacji bez zapisania trzeba obsłużyć w zasadzie tylko w 2 miejscach: na ekranie dodawania nowego wpisu i edycji istniejącego.
Teoria
W teorii należy skorzystać z metod OnSleep
i OnResume
. Pierwsza uruchamiana jest przy wychodzeniu z aplikacji np. poprzez naciśnięcie przycisku Home. Druga natomiast przy powrocie do uruchomionej aplikacji. To one służą do zapisu i odczytu danych jak i np. wznawiania połączenia z bazą danych.
Zalecane rozwiązanie
Jednak zalecanym rozwiązaniem jest w klasie App
utworzenie properisa/-ów, który będzie aktualizowany poprzez inne ekrany, a tylko zapisywany przez powyższe metody. Takie rozwiązanie przyjąłem i ja. Problem polega na tym, że na etapie pisania kodu nie wiem ile muszę utworzyć tych propertisów, żeby objąć wszystkie pola do wprowadzania. Pisałem już o tym we wpisie o dynamicznym generowaniu UI.
Postanowiłem więc zostawić jedną zmienną typu string w klasie App
, którą nazwałem StoredData
. Do niej wkładane będą dane w formacie JSON. Przy każdym uśpieniu aplikacji ta zmienna będzie zapisywana do Properisa aplikacji. Jest to specjalne miejsce, gdzie można trzymać ustawienia, czy właśnie tymczasowe dane aplikacji. Dane trzymane są tam tylko w podstawowych typach(string, int i double). Te propertisy to tak w zasadzie słownik – struktura danych zawierająca pary typu klucz-wartość.
Gdy praca aplikacji będzie wznawiana będzie sprawdzane, czy Propertisy nie zawierają podanego klucza. Jeśli taki klucz istnieje, będzie przypisywany do zmiennej StoredData
.
Kod za to odpowiedzialny znajduje się w klasie App
i wygląda tak:
const string storedDataName = "storedData"; public string StoredData { get; set; } = null; protected override void OnSleep() { Properties[storedDataName] = StoredData; } protected override void OnResume() { if (Properties.ContainsKey(storedDataName)) StoredData = (string)Properties[storedDataName]; else StoredData = null; }
Reszta logiki odpowiedzialnej za wczytywanie i zapisywanie danych przy wychodzeniu znajduje się w odpowiednich klasach. Są to klasy definiujące widoki dodawania nowego i edycji istniejącego wpisu.
Skorzystałem z tego, że Edytor z którego Codziennik korzysta do wprowadzania odpowiedzi na pytania ma akcje TextChanged
. Jest ona odpalana za każdym razem, gdy tekst Edytora się zmieni. Podpiąłem do tej akcji taką metodę:
void SaveProperties(object sender, EventArgs e) { entry.Answers = new List<string>(); foreach (Editor editor in answersEditors) { entry.Answers.Add(editor.Text); } entry.SetEntryDateNow(); app.StoredData = JsonConvert.SerializeObject(entry); }
Wygląda ona w zasadzie tak samo, jak metoda służąca do zapisywania o której mówiłem w tym wpisie. Różnicą jest to, że zamiast używać metody z klasy do obsługi plików, parsuje wpis do JSONa, żeby przypisać go do zmiennej StoredData
, o której pisałem wyżej.
Jest to sposób bardzo prosty, ale to dobrze. Często rozwiązania bardzo wymyślne lubią się psuć. Zresztą parsowanie rozbudowanych danych do np. JSONa żeby zapisać je w Properties jest metodą zalecaną w książce „Creating Mobile Apps with Xamarin.Forms„. Jest to bardzo dobra lektura, którą odkryłem niedawno. Zawiera dużo przykładów i propozycji poprawnych rozwiązań kwestii, których próżno szukać w oficjalnej dokumentacji Xamarin.Forms. Szczerze polecam tą książkę, każdemu kto zajmuje się Xamarin.Forms.
Jak zawsze kod źródłowy można znaleźć na moim Githubie w tym repozytorium. Ta wersja została oznaczona tagiem 05-onsleep. Przechodząc pod niego można zobaczyć jak wyglądał kod aplikacji Codziennik podczas pisania tego posta.