Persistence in Android
Shared Preferences
You can use shared preferences to save arbitrarily data on the device.
Saving sensitive information
Please do not save sensitive information in shared preferences since they are stored in plain text files on the device.
To save preferences you use the ISharedPreferences
interface.
Get the default shared preferences
The default shared preferences are saved in a file thats prefixed your your app's package name. To get the default shared preferences use the the SharedPreferenceManager
class as follows:
1 | var sharedPreferences = PreferenceManager.GetDefaultSharedPreferences(this); |
Then you can use the ISharedPreferencesEditor
to add the preferences as follows:
1 | var editor = sharedPreferences.Edit(); |
You can now use the editor to put the preferences using a key/value pair as follows :
1 | editor.PutString("NICKNAME", "joseph"); |
You should call Commit()
or Apply()
when done to apply the change. Apply()
commits the changes asynchronously.
Creating a shared preference file
You can also create a named shared preferences file instead of using the default one. You use the GetSharedPreferences()
method and supply a name of the preferences file and the mode to create it as follows:
1 | var namesSharedPrefs = GetSharedPreferences("colors", FileCreationMode.Private); |
You can perform the same operations as with the default shared preferences.
Restoring shared preferences
To get the shared preferences, first get the shared preference and use the various get methods to retrieve the preferences as follows:
1 | var nickname = sharedPreferences.GetString("NICKNAME", "defaultValue"); |
You need to specify a default value if the preference is not found.
Clearing shared preferences
You can clear all the preferences by calling the Clear()
method on the ISharedPreferenceEditor
of the shared preferences as follows:
1 | sharedPreferences.Edit().Clear().Apply(); |
We also called Apply()
to commit the changes.
Listening for preference changes
You can register a listener to be notified when the preferences changes using the RegisterOnSharedPreferenceChangeListener()
method on the shared preferences. You will need to implement the interface ISharedPreferencesOnSharedPreferenceChangeListener
as follows:
1 | PreferenceManager.GetDefaultSharedPreferences(this).RegisterOnSharedPreferenceChangeListener(this); |
and then implementing the interface on the activity as follows :
1 2 3 4 5 6 | public class LoginActivity : AppCompatActivity, ISharedPreferencesOnSharedPreferenceChangeListener { public void OnSharedPreferenceChanged(ISharedPreferences sharedPreferences, string key) { ... } } |
Adding a Setting Screen Using PreferenceFragmentCompat
They are several ways to add a Settings/Preference Screen to your app :
- Use the PreferenceActivity
- Use the PreferenceFragment
- Use the PreferenceFragmentCompat
Adding an xml Resource File
For both methods you will need an an xml resource file to be added into the Resources folder under the xml directory.
- Create the xml folder if it does not yet exists under the Resources directory
- Create a new xml resource file into the just created xml resource directory or use the existing one.
- Add the preferences. The preferences have the equivalent names to their views with the additional Preference suffix, e.g to add an EditText preference you use EditTextPreference. Also preferences use keys instead of id since they are stored as key/value pairs
Resources/xml/prefs.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:title="General"> <EditTextPreference android:key="nickname" android:title="Nickname" /> </PreferenceCategory> <PreferenceCategory android:title="Notifications"> <SwitchPreference android:title="Notifications" android:summary="Get notifications when you receive messages" android:key="notifications" android:defaultValue="true" /> <RingtonePreference android:defaultValue="content://settings/system/notification_sound" android:dependency="notifications" android:key="user_joined" android:title="User Joined" android:summary="Alert for when a user joins the chat" android:ringtoneType="notification" /> <RingtonePreference android:defaultValue="content://settings/system/notification_sound" android:dependency="notifications" android:key="user_left" android:title="User Left" android:summary="Alert for when a user leaves the chat" android:ringtoneType="notification" /> <RingtonePreference android:defaultValue="content://settings/system/notification_sound" android:dependency="notifications" android:key="mew_message" android:title="New Message" android:summary="Alert for when a new message arrives" android:ringtoneType="notification" /> </PreferenceCategory> </PreferenceScreen> |
The settings UI is defined inside the following tags :
1 2 3 | <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> ... </PreferenceScreen> |
Adding Categories
We add categories to the settings UI by using the
1 2 3 | <PreferenceCategory android:title="General"> ... </PreferenceCategory> |
Adding a Switch Preference
1 2 3 4 5 | <SwitchPreference android:title="Notifications" android:summary="Get notifications when you receive messages" android:key="notifications" android:defaultValue="true" /> |
Adding a Ringtone Preference
The ringtone preference will load the phone ringtones settings into your settings screen and lets the user pick a ringtone. You can also add a default ringtone
1 2 3 4 5 6 7 | <RingtonePreference android:defaultValue="content://settings/system/notification_sound" android:dependency="notifications" android:key="user_joined" android:title="User Joined" android:summary="Alert for when a user joins the chat" android:ringtoneType="notification" /> |
Adding a Settings Screen using PreferenceActivity
The easiest way to add a settings screen is to create an activity that inherits from the PreferenceActivity class. We will use the xml resource defined above.
- Create a new Activity
- Inherit from PreferenceActivity instead of Activity or AppCompatActivity
- n the OnCreate method, instead of setting the SetContentView method use AddPreferencesFromResource method. Notice this method is deprecated, so you will need to use the other methods.
PrefsActivity.cs
1 2 3 4 5 6 7 8 9 | [Activity(Label = "PreActivity")] public class PrefsActivity : PreferenceActivity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); AddPreferencesFromResource(Resource.Xml.prefs); } } |
Add a Menu option to Open the Settings Screen
You will need to define a menu so you can use it to open the settings screen.
- Add the menu folder in the Resources folder if one does not yet exist
- Create a menu.xml file
1 2 3 4 5 6 | <?xml version="1.0" encoding="UTF-8" ?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/action_menu" android:title="Settings" /> </menu> |
We will use the defined id on the menu to find which menu option have been selected.
Modify the activity you want to be able to access the settings from and create the menu.
MainActivity.cs
1 2 3 4 5 6 | //Create the options menu public override bool OnCreateOptionsMenu(Android.Views.IMenu menu) { MenuInflater.Inflate(Resource.Menu.menu, menu); return base.OnCreateOptionsMenu(menu); } |
Handle the menu selection as follows :
1 2 3 4 5 6 7 8 9 | //Handle the selecting of the options menu public override bool OnOptionsItemSelected(Android.Views.IMenuItem item) { var id = item.ItemId; if (id == Resource.Id.action_menu) { StartActivity(new Android.Content.Intent(this, typeof(PrefsActivity))); } return true; } |
Now when you run you should be able to get an option item called Settings. When click it, the settings screen should load up.
Adding a Settings Screen Using a PreferenceFragment
Use the following steps to create a settings screen using the PreferenceFragment :
- Create a class that derives from
PreferenceFragment
- In the OnCreate method use the AddPreferenceFromResource method to inflate the preference xml file PrefsFragment.cs
1 2 3 4 5 6 7 8
public class PrefsFrgament : PreferenceFragment { public override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); AddPreferencesFromResource(Resource.Xml.prefs); } }
- In the activity you would like to show the preference, replace an exisiting container, usually FrameLayout with the PrefsFragment
Resources/layout/activity_main.axml
1 2 3 4 5 6 7 8 9 10 | <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/content" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> |
PrefsActivity.cs
Use the FragmentManager to replace the FrameLayout with the PrefsFragment
1 2 3 4 | FragmentManager .BeginTransaction() .Replace(Resource.Id.content, new PrefsFragment()) .Commit(); |
PrefsActivity.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | using Android.App; using Android.OS; using Android.Support.V4.App; using Android.Support.V7.App; using Android.Views; namespace sharedPreferenceDemo { [Activity(Label = "PrefsActivity", Theme = "@style/AppTheme", ParentActivity = typeof(MainActivity))] [MetaData("android.support.PARENT_ACTIVITY", Value = "md51c3958e33f8e72dae9076079df527ba2.MainActivity")] public class PrefsActivity : AppCompatActivity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.activity_prefs); FragmentManager .BeginTransaction() .Replace(Resource.Id.content, new PFrgament()) .Commit(); if (SupportActionBar != null) { SupportActionBar.SetDisplayHomeAsUpEnabled(true); } } public override bool OnOptionsItemSelected(IMenuItem item) { if (item.ItemId == Android.Resource.Id.Home) { NavUtils.NavigateUpFromSameTask(this); } return base.OnOptionsItemSelected(item); } } } |
Adding Up Arrow for Back Navigation
In the Oncreate method we check if we have an ActionBar and set the up arrow to display :
1 2 3 | if (SupportActionBar != null) { SupportActionBar.SetDisplayHomeAsUpEnabled(true); } |
Then we handle the clicking of the up arrow in the OnOptionsItemSelected methods :
1 2 3 4 5 6 7 | public override bool OnOptionsItemSelected(IMenuItem item) { if (item.ItemId == Android.Resource.Id.Home) { NavUtils.NavigateUpFromSameTask(this); } return base.OnOptionsItemSelected(item); } |
Adding a Parent Activity
In oder to go back to a parent activity when we click the up arrow, we need to add attribute to the activity. We specify the ParentActivity
1 | [Activity(Label = "PrefsActivity", Theme = "@style/AppTheme", ParentActivity = typeof(MainActivity))] |
For this to also work on older devices, we have to use a MetaData attribute and use the the name as android.support.PARENT_ACTIVITY and the value to be fully qualified name of the activity to navigate back to.
1 | [MetaData("android.support.PARENT_ACTIVITY", Value = "md51c3958e33f8e72dae9076079df527ba2.MainActivity")] |
You can find the MD5Sum, md51c3958e33f8e72dae9076079df527ba2
of the activity by check the generated AndroidManifest.xml
file in the obj folder