Android Base de Données

Les fichiers de préférences, SharedPreferences, correspondent aux fichiers de paramètres de l’application. Ils sont utilisés pour sauvegarder des données persistantes, utiles pour le fonctionnement de l’application. C’est la première solution à envisager lorsqu’on souhaite sauvegarder des données.

En particulier, ces fichiers de préférences permettent de stocker des données sous la forme de couple clé, valeur (où clé est de type String, permettant de référencer la valeur, et valeur est une donnée primitive telle qu’un Integer, un Boolean, ou un  String). Ces derniers sont consultables durant l’exécution et persistent après la fermeture de l’application. Un des intérêts est de pouvoir y accéder depuis n’importe quelle classe ayant accès au contexte de l’application, notamment depuis une Activity ou un Fragment.

Par exemple, pour une application destinée à un seul utilisateur, il serait intéressant d’y stocker le profil de ce dernier (préférence de son, âge, sexe, etc.). Cet article détaille comment créer un écran de paramètre, permettant d’enregistrer le paramètre audio de l’utilisateur. Ensuite, il s’agit de récupérer la valeur de ce paramètre, à partir de fonctions natives du SDK Android. Puis, il est élaboré l’écriture dans un fichier de préférence, sans passer par une interface utilisateur. Enfin, il est utilisé une classe déléguée Kotlin afin de simplifier l’utilisation des SharedPreferences.

Ajouter un écran de paramètre

Tout d’abord, il s’agit de créer la vue XML spécifique aux préférences, Preferences [1]. Ensuite, cette vue devra être liée à une classe héritant de PreferencesFragment.

  1. Ajoutez un dossier de ressource dans le dossier res/ via Android Studio, nommé le xml/ (spécifier xml pour son type).
  2. Ajoutez un fichier XML settings.xml dans le dossier venant d’être créé :

     <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
     </PreferenceScreen>
    
  3. Ajoutez un bouton à bascule, à l’intérieur des balises <PreferenceScreen>. Il représente le paramètre audio, avec comme clé, @string/pref_sound et valeur par défaut, true :

     <SwitchPreference
     android:defaultValue="true"
     android:key="@string/pref_sound"
     android:title="@string/label_sound" />
    
  4. Ajoutez une nouvelle classe Kotlin, SettingsFragment, elle hérite de PreferencesFragment :

     class SettingsFragment : PreferenceFragment() {
         override fun onCreate(savedInstanceState: Bundle?) {
             super.onCreate(savedInstanceState)
         }
     }
    
  5. Liez le fichier settings.xml à SettingsFragment, via la fonction addPreferencesFromResource(), à appeler depuis la méthode onCreate() :

     addPreferencesFromResource(R.xml.settings)
    
  6. Chargez la valeur entrée par défaut dans settings.xml dans le fichier SharedPreferences de défaut (depuis une Activity ou un Fragment) :

     PreferenceManager.setDefaultValues(this, R.xml.settings, false)
    

À présent, le fichier SharedPreferences de défaut contient un couple de clé, valeur (@string/pref_sound, true). La valeur associée à la clé @string/pref_sound sera automatiquement mise à jour en fonction des interactions de l’utilisateur avec cet écran de paramètre.

Lire le fichier de préférence de défaut

Afin de récupérer la valeur précédemment stockée, il faut cibler le fichier SharedPreferences de défaut. Ensuite, il s’agit de récupérer la valeur via la fonction de lecture appropriée (getInt(), getBoolean() ou getString(), etc.), cela depuis une Activity ou un Fragment.

  1. Récupérez le fichier SharedPreferences de défaut, dans une variable defaultSharedPref :

     var defaultSharedPref = PreferenceManager.getDefaultSharedPreferences(this)
    
  2. Récupérez la valeur associée à la clé @string/pref_sound :

     defaultSharedPref.getBoolean(getString(R.string.pref_sound), true)
    

D’une part, les fichiers de préférences peuvent être ouvert en lecture afin d’y récupérer les données préalablement enregistrées. D’autre part, ces fichiers peuvent être ouvert en écriture (ou édition).

Écrire dans un des fichiers de préférence

Afin d’écrire dans un fichier de préférence, il s’agit de cibler un des fichiers, puis de récupérer son éditeur [3]. A ce moment, il est possible de modifier, ajouter ou supprimer des couples de clé, valeur.

  1. Ciblez un fichier de préférence, sans nom, dans un mode privé (seule votre application y aura accès) :

     var sharedPref = getPreferences(Context.MODE_PRIVATE)
    
  2. Récupérez l’éditeur :

     var editor: SharedPreferences.Editor = sharedPref.edit()
    
  3. Insérez un nombre :

     editor.putInt(App.PREF_NB, nb)
    

    avec App.PREF_NB une constante de type String.

  4. Validez le changement apporté au fichier :

     editor.commit()
    

Il est également possible de nommer un fichier de préférence :

var sharedPref = getPreferences("user", Context.MODE_PRIVATE)

De plus, il est possible d’autoriser l’accès d’un fichier de préférence à d’autres applications :

var sharedPref = getPreferences(Context.MODE_WORLD_WRITEABLE)

Par ailleurs, à l’instar des fonctions de lecture, il y a les fonctions d’écriture, selon le type pris par la valeur (putInt(), putBoolean() ou putString(), etc.).

Plus loin avec Kotlin

De façon à faciliter l’ajout, la modification et la lecture de couple clé, valeur, il est intéressant d’utiliser une classe déléguée Kotlin.

  1. Ajoutez un fichier Kotlin DelegatesExt :

     object DelegatesExt {
         fun <T> preference(context: Context, name: String,
                    default: T) = Preference(context, name, default)
         fun <T> preference(fragment: Fragment, name: String,
                    default: T) = Preference(fragment, name, default)
     }
    
  2. Dans ce fichier [5], à la suite, ajoutez la classe avec un type réifié Preference<T> :

     class Preference<T>(private var context: Context?, private val name: String,
                 private val default: T) {
         var myFragment: Fragment? = null
         constructor(fragment: Fragment, name: String, default: T) : this(null, name, default) {
             myFragment = fragment
         }
    
         private val prefs: SharedPreferences by lazy {
             if (myFragment == null)
                 PreferenceManager.getDefaultSharedPreferences(context)
             else
                 PreferenceManager.getDefaultSharedPreferences(myFragment!!.activity)
         }
    
         operator fun getValue(thisRef: Any?, property: KProperty<*>): T = findPreference(name, default)
    
         operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
             putPreference(name, value)
         }
    
         @Suppress("UNCHECKED_CAST")
         private fun findPreference(name: String, default: T): T = with(prefs) {
             val res: Any = when (default) {
                 is Long -> getLong(name, default)
                 is String -> getString(name, default)
                 is Int -> getInt(name, default)
                 is Boolean -> getBoolean(name, default)
                 is Float -> getFloat(name, default)
                 else -> throw IllegalArgumentException("This type can be saved into Preferences")
             }
             res as T
         }
    
         @SuppressLint("CommitPrefEdits")
         private fun putPreference(name: String, value: T) = with(prefs.edit()) {
             when (value) {
                 is Long -> putLong(name, value)
                 is String -> putString(name, value)
                 is Int -> putInt(name, value)
                 is Boolean -> putBoolean(name, value)
                 is Float -> putFloat(name, value)
                 else -> throw IllegalArgumentException("This type can't be saved into Preferences")
             }.apply()
         }
     }
    
  3. Utilisez cette classe déléguée, depuis une Activity ou un Fragment, en déclarant une variable (représentant le nom de l’utilisateur, par exemple) :

     var userName: String by DelegatesExt.preference(this, App.PREF_NAME, "John")
    
  4. Modifiez cette variable userName, cela aura pour effet de modifier le fichier SharedPreferences de défaut :

     userName = "Macha"
    

Finalement, cet article présente l’utilisation des fichiers de préférence pour des paramètres nécessitant une interface utilisateur ainsi que pour des paramètres invisibles par ce dernier. De plus, il présente une classe déléguée permettant de simplifier l’utilisation du fichier SharedPreferences de défaut depuis une Activity ou un Fragment.

Références

  1. Android Documentation: Settings
  2. Material Design: Settings
  3. Android Documentation: Save Key-Value Data with SharedPreferences
  4. Antonio Leiva: DelegatesExt
  5. DelegatesExt by macha on Gitlab
  6. Correction sur GitLab : MR 7 Shared Preferences

Partagez ou réagissez sur Twitter.

Vous avez trouvé une erreur ou voulez améliorer cet article ? Editez le directement !

Comments