I'll admit, until recently, I was blissfully unaware that Xamarin.Forms has a baked-in persistence mechanism in the form of a static IDictionary
object in the App
class.
This property is called, of all things, Properties
and has the signature of IDictionary<string, object>
. You can use it for persistent storage of whatever you'd like (and I'll get to how below). And it is perfect for storing things such as user preferences.
How To Use App.Properties
The Application
class defines the Properties
property as static. It also defines another property Current
, which returns the current, running instance of the Application
as static.
Then to get at the Properties
and all of the persistence that it provides, all one needs to do is acces App.Current.Properties
anywhere in their Xamarin.Forms application to get at the persisted storage.
Essentially App.Current.Properties
is a global variable, available everywhere. (Whether you should use it within view models, or deep in your app is an architectural question - which I'll leave up to you!)
Reading Data
Reading data out of the App.Current.Properties
dictionary is the same as reading out of any regular dictionary that you're already used to.
You want to first make sure the key exists in the dictionary - read the value out via the key if it does - then cast the value over to the type it should be.
string fullRecipe;
if (App.Current.Properties.Exists("ScrambledEggsRecipe"))
{
fullRecipe = App.Current.Properties["ScrambledEggsRecipe"] as string;
}
Pretty straight forward.
Writing Data
Again, much like reading data, writing data to the App.Current.Properties
is the same as writing data to a normal dictionary.
First you'll want to see if the key already exists, if not, use the Add
function of the IDictionary
.
If the key does exist - then write over the top of the existing item.
string fullRecipe = "this is a delicious recipe that has been handed down through my family for years and years";
if (App.Current.Properties.Exists("ScrambledEggsRecipe"))
App.Current.Properties["ScrambledEggsRecipe"] = fullRecipe;
else
App.Current.Properties.Add("ScrambledEggsRecipe", fullRecipe);
Because the App.Current.Properties
is defined as IDictionary<string,object>
there is no need to case the fullRecipe
variable to any other type.
Saving Data
It should be noted that adding or updating an entry in the App.Current.Properties
dictionary does not automatically persist it to permanent storage.
There are two ways to save data using the App.Current.Properties
.
The first is the Application
object gives a function called SavePropertiesAsync()
. This will force everything in the Properties
dictionary to be written and is advisable to be called as soon as after something important is written to the dictionary.
The second way the Properties
dictionary gets persisted is to let Xamarin.Forms automatically do it.
In the OnSleep()
function of the Application
object - the contents of the Properties
object will be persisted out.
This means that whenever your app gets backgrounded, the contents of App.Current.Properties
will be saved - this is a safety fall-back to make sure everything gets persisted and is there the next time your app is launched.
Gotchas
Ah - but all is not well and easy in the land of easy persistence in Xamarin.Forms!
There are a couple of gotchas that you need to be aware of in order to make the App.Current.Properties
persistence work for you - instead of you fighting it.
Can Only Save Primitives - Or Can It?
Despite the face that App.Current.Properties
is defined as IDictionary<string, object>
... it cannot take any object as a value.
It can only save primitive data types.
You know, int
, string
, double
... and while that's all well and fine - and will probably serve most of your needs - especially if all you're using it for is user settings, what happens if you need it to save something a little more complex?
Luckily - there is something that is wonderful at representing an object as a primitive type ... or a string
... and that is ... JSON!!
And through the wonderful library of JSON.Net - it's super easy to take any object graph, serialize it to JSON, and then persist it in the App.Current.Properties
!!
So ... let's say instead of only having a string
for a recipe above, we have a full object like the following:
public class Recipe
{
public string Id { get; set; }
public string Directions { get; set; }
public int CookTime { get; set; }
public int NumberOfServings { get; set; }
}
Without JSON, I would be out of luck trying to put that into the App.Current.Properties
dictionary. But with it... I can do something like this (assuming JSON.Net has been added as a reference to the project).
var recipe = new Recipe {
Id = Guid.NewGuid().ToString(),
Directions = "Super secret family recipe",
CookTime = 5,
NumberOfServings = 2
};
var recipeJson = JsonConvert.SerializeObject(recipe);
App.Current.Properties.Add(recipe.Id, recipeJson);
And now the App.Current.Properties
is able to hold complex objects.
Of course, you don't want to replicate a whole database in here ... so you do need to be judicious in your use of this - but it is useful for a very limited needs.
Watch Out While Debugging!
Another issue that you'll encounter is that while debugging the OnSleep()
function will not get called if you hit Stop in the IDE.
This can lead to some frustration as to why some settings are present in App.Current.Properties
when you think they should be there - especially if you are not currently in the process of debugging them - but rather working on something else and just expect those to work!
One way around it is to always call App.Current.SaveProperitesAsync()
after every write ... or just be aware that hitting Stop in the debugger won't do the save.
Summary
I didn't know that App.Current.Properties
even existed until I happened across it in the documentation a couple of weeks ago.
I used to always go for the Settings plug-in to persist minor data within Xamarin.Forms apps ... but now I think I may change my ways and use this instead!
Just be aware that persisting an object takes a bit of work - and probably isn't advisable in the first place, and that you need to explicitly save the properties out while debugging, otherwise they may not be there when you think they should be.
Otherwise - it's like using a regular IDictionary
object!
Comments