Artykuł

freeimages.com freeimages.com
paź 03 2015
0

Zapisywanie danych użytkownika w Universal Apps

W chwili obecnej tworząc aplikacje mobilne, bardzo często korzystamy z Internetu, o czym wspominałem po części w ostatnim wpisie. Siłą rzeczy w chmurze często trzymamy też konfigurację aplikacji/usługi, aczkolwiek nie musi to być regułą. Aplikacje uniwersalne obsługują bowiem tzw kontenery danych (ApplicationDataContainer), które pozwalają na zapisywanie ustawień dla konkretnej instalacji, a także globalnie dla naszego konta Windows Live. W dzisiejszym wpisie, zaprezentuję prosty sposób na wykorzystanie tych mechanizmów w praktyce.

Local vs Roaming

Aplikacje uniwersalne umożliwiają przechowywanie danych za pomocą dwóch kontenerów:

Ustawienia zapisywane w kontenerach, przechowywane są w postaci słownikowej. Korzystając z tych rozwiązań, musimy spełnić poniższe kryteria:

  • Długość klucza musi się mieścić w 255 znakach
  • Pojedyncze ustawienie musi się mieścić w 8KB dla typów prostych, lub w 64KB dla obiektów złożonych

W przypadku kontenera Local, ustawienia zapisywane są dla określonego urządzenia. Nie oznacza to jednak, że zapisywane są one tylko lokalnie - są one synchronizowane z kontem Microsoftu. W sytuacji jeśli odinstalujemy aplikację, a następnie zainstalujemy ją ponownie (np. po formacie telefonu), to zostaną one automatycznie zsynchronizowane z chmury MS. W przypadku ustawień lokalnych, nie mamy zasadniczego ograniczenia w ilości zapisywanych wartości.

Ustawienia typu Roaming, są wspólne pomiędzy wszystkimi urządzeniami użytkownika. W pewnym sensie można wykorzystać je do prostej synchronizacji danych. Np. jeśli tworzymy odtwarzacz multimedialny, możemy zapisać postęp odtwarzanej piosenki, do której będziemy mogli później wrócić dokładnie w tym samym momencie na innym sprzęcie;-)

Interfejs oraz klasa abstrakcyjna

Na potrzeby obsługi obu kontenerów, stworzyłem prosty interfejs oraz klasę, która abstrakcyjną, która go implementuje. Zaczniemy od tego pierwszego:

public interface ISettingsManager
{
    T Load<T>(string key);
    T Load<T>(string key, T defaultValue);
    object Load(string key);
    void Save(string key, object value);
    void RemoveSetting(string key);
    void ClearAllSettings();
}

Poszczególne metody pozwalają na (kolejność według kodu):

  • Wczytywanie generycznego obiektu o określonym kluczu
  • j/w + obsługa wartości domyślnej wskazanej przy wywołaniu
  • Wczytywanie obiektu o określonym kluczu
  • Zapisywanie wybranego obiektu
  • Usuwanie ustawienia o określonym kluczu
  • Usuwanie wszystkich ustawień

Powyższy interfejs implementowany jest przez klasę abstrakcyjną, które później z kolei rozszerzana jest przez konkretne implementacje:

public abstract class SettingsManager : ISettingsManager
{
    protected ApplicationDataContainer storageContainer = null;

    public SettingsManager(ApplicationDataContainer storageContainer)
    {
        this.storageContainer = storageContainer;
    }

    public T Load<T>(string key)
    {
        object ret = Load(key);
        if (ret == null)
        {
            return default(T);
        }
        return (T)ret;
    }

    public T Load<T>(string key, T defaultValue)
    {
        object ret = Load(key);
        if (ret == null)
        {
            return defaultValue;
        }
        return (T)ret;
    }

    public object Load(string key)
    {
        object output = null;
        storageContainer.Values.TryGetValue(key, out output);
        return output;
    }

    public void Save(string key, object value)
    {
        if (storageContainer.Values.ContainsKey(key))
        {
            storageContainer.Values[key] = value;
        }
        else
        {
            storageContainer.Values.Add(key, value);
        }
    }

    public void RemoveSetting(string key)
    {
        if (storageContainer.Values[key] != null)
        {
            storageContainer.Values.Remove(key);
        }
    }

    public virtual void ClearAllSettings()
    {
        storageContainer.Values.Clear();
    }
}

Rozróżnienie z perspektywy obsługi typów Local/Roaming, znajdzie swoje miejsce w klasach konkretnych.

Konkretne implementacje

Zwieńczeniem kodu managera, są dwie konkretne implementacje dla obsługi ustawień lokalnych oraz globalnych. Poniżej kod:

public class LocalSettingsManager : SettingsManager
{
	public LocalSettingsManager()
		: base(ApplicationData.Current.LocalSettings)
	{
	}
}

public class RoamingSettingsManager : SettingsManager
{
	public RoamingSettingsManager()
		: base(ApplicationData.Current.RoamingSettings)
	{
	}
}

Jedyną różnicą między obiema klasami, jest inny folder przekazany w konstruktorze.

Użycie

Użycie jest bardzo proste. Wystarczy utworzyć odpowiednią instancję obiektu, a później wywołać jedną z sześciu metod;-) Poniżej przykładowe wywołania:

ISettingsManager manager = new LocalSettingsManager();
manager.Save("UserAgreement", true);
bool userAgreement1 = manager.Load<bool>("UserAgreement");
bool userAgreement2 = manager.Load<bool>("UserAgreement", false);
bool userAgreement3 = Convert.ToBoolean(manager.Load("UserAgreement"));

W przypadku klasy RoamingSettingsManager, sytuacja wygląda identycznie.

Podoba Ci się ten wpis? Powiedz o tym innym!

Send to Kindle

Komentarze

blog comments powered by Disqus