13 - Almacenamiento de datos mediante la clase SharedPreferences

La plataforma de Android nos da varias facilidades para el almacenamiento permanente de datos (es decir que los mismos no se borran cuando se apaga o cierra la aplicación)

Según el tipo de necesidades utilizaremos alguno de estos métodos:

  1. Mediante la clase SharedPreferences.
  2. Mediante archivos de Texto.
  3. En una base de datos con acceso a SQL.

No será raro que una aplicación utilice más de uno de estos métodos para el almacenamiento de datos.

Cuando tenemos que almacenar una cantidad limitada de datos es adecuado utilizar la clase SharedPreferences. Por ejemplo configuraciones de la aplicación como pueden ser colores de pantalla, nivel actual en un juego, datos iniciales de controles de entrada etc.

Problema 1:

Confeccionar un programa que solicite el ingrese del mail de una persona. Guardar el mail ingresado utilizando la clase SharedPreferences. Cada vez que se inicie la aplicación almacenar en el control EditText el último mail ingresado. Disponer un botón para almacenar el mail ingresado y finalizar el programa.

Crearemos un nuevo proyecto llamado proyecto013.

La interfaz visual a implementar es:

clase SharedPreferences

Tenemos las componentes:

 
Disponemos un EditText  (ID="et1", hint="Ingrese mail")
Disponemos un Button    (ID="boton1", text="EJECUTAR")

El código Kotlin es:

package com.tutorialesprogramacionya.proyecto013

import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val et1=findViewById<EditText>(R.id.et1)
        val preferencias = getSharedPreferences("datos", Context.MODE_PRIVATE)
        et1.setText(preferencias.getString("mail", ""))
        val boton1=findViewById<Button>(R.id.boton1)
        boton1.setOnClickListener {
            val editor = preferencias.edit()
            editor.putString("mail", et1.text.toString())
            editor.commit()
            finish()
        }
    }
}

Obtenemos una referencia de un objeto de la clase SharedPreferences a través del método getSharedPreferences heredado de la clase AppCompatActivity. El primer parámetro es el nombre del archivo de preferencias y el segundo la forma de creación del archivo (MODE_PRIVATE indica que solo esta aplicación puede consultar el archivo XML que se crea)

        val preferencias = getSharedPreferences("datos", Context.MODE_PRIVATE)

Para extraer los datos del archivo de preferencias debemos indicar el nombre a extraer y un valor de retorno si dicho nombre no existe en el archivo de preferencias (en nuestro ejemplo la primera vez que se ejecute nuestro programa como es lógico no existe el archivo de preferencias lo que hace que Android lo cree, si tratamos de extraer el valor de mail retornará el segundo parámetro es decir el String con una cadena vacía:

        et1.setText(preferencias.getString("mail", ""))

Cuando se presiona el botón "confirmar" lo que hacemos es grabar en el archivo de preferencias el contenido del EditText en una variable llamada "mail":

        boton1.setOnClickListener {
            val editor = preferencias.edit()
            editor.putString("mail", et1.text.toString())
            editor.commit()
            finish()
        }

Debemos crear un objeto de la clase Editor y obtener la referencia del objeto de la clase SharedPreferences que acabamos de crear. Mediante el método putString almacenamos en mail el valor del String cargado en el EditText. Luego debemos llamar al método commit de la clase Editor para que el dato quede almacenado en forma permanente en el archivo de preferencias. Esto hace que cuando volvamos a arrancar la aplicación se recupere el último mail ingresado.

Recordemos que el método finish de la clase AppCompatActivity finaliza la actividad actual (como tenemos una aplicación con una sola actividad finalizará completamente nuestro programa)

Este proyecto lo puede descargar en un zip desde este enlace: proyecto013.zip

Cuando guardamos datos en el archivo de preferencias podemos almacenar distintos tipos de datos según el método que llamemos en el momento de grabar:

            editor.putInt("edad",3)
            editor.putBoolean("activo", true)
            editor.putFloat("altura", 2.3f)

Cuando los recuperamos debemos indicar también que tipo de datos extraemos:

            val e = preferencias.getInt("edad", 0)
            val acti = preferencias.getBoolean("activo", false)
            val alt = preferencias.getFloat("altura", 0f)

Problema 2:

Confeccionar un programa que permita administrar una agenda personal. Nuestra clave será el nombre de la persona.

Crearemos un nuevo proyecto llamado proyecto014.

La interfaz visual a implementar será similar a esta:

clase SharedPreferences
  EditText de tipo Plain Text (ID=et1, hint="Nombre de la persona", text="")
  EditText de tipo Multiline Text (ID=et2, hint="datos")
  Button ( ID="boton1", text="GRABAR")
  Button ( ID="boton2", text="RECUPERAR")

El código fuente en Kotlin es:

package com.tutorialesprogramacionya.proyecto014

import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val et1=findViewById<EditText>(R.id.et1)
        val et2=findViewById<EditText>(R.id.et2)
        val preferencias = getSharedPreferences("agenda", Context.MODE_PRIVATE)
        val boton1=findViewById<Button>(R.id.boton1)
        boton1.setOnClickListener{
            val editor = preferencias.edit()
            editor.putString(et1.text.toString(), et2.text.toString())
            editor.commit()
            Toast.makeText(this, "Datos grabados", Toast.LENGTH_LONG).show()
            et1.setText("")
            et2.setText("")
        }
        val boton2=findViewById<Button>(R.id.boton2)
        boton2.setOnClickListener {
            val datos = preferencias.getString(et1.text.toString(), "")
            if (datos != null) {
                if (datos.length == 0)
                    Toast.makeText(this, "No existe dicho nombre en la agenda", Toast.LENGTH_LONG).show()
                else
                    et2.setText(datos)
            }
        }
    }
}

Obtenemos la referencia del archivo de preferencias llamado "agenda":

        val preferencias = getSharedPreferences("agenda", Context.MODE_PRIVATE)

Cuando se presiona el botón de grabar creamos un objeto de la clase Editor llamando al método edit del objeto preferencias:

        boton1.setOnClickListener{
            val editor = preferencias.edit()

Grabamos en el archivo de preferencias como clave el nombre de la persona almacenado en el et1 y como valor el dato almacenado en el et2:

            editor.putString(et1.text.toString(), et2.text.toString())

Finalmente confirmamos la grabación en el archivo de preferencias llamando al método commit:

            editor.commit()

Mostramos al operador del programa un mensaje indicando que los datos fueron almacenados y borramos de pantalla el contenido de los dos EditText:

            Toast.makeText(this, "Datos grabados", Toast.LENGTH_LONG).show()
            et1.setText("")
            et2.setText("")

Cuando se presiona el botón de recuperar buscamos en el archivo de preferencias si hay alguna clave con el nombre cargado en el et1:

        boton2.setOnClickListener {
            val datos = preferencias.getString(et1.text.toString(), "")

Si en la variable datos tiene cero caracteres luego podemos mostrar al operador que no hay una persona con el nombre ingresado:

            if (datos != null) {
                if (datos.length == 0)
                    Toast.makeText(this, "No existe dicho nombre en la agenda", Toast.LENGTH_LONG).show()

En caso contrario mostramos los datos recuperados en el et2:

                else
                    et2.setText(datos)
            }

En el emulador podemos ver como ingresamos y recuperamos datos de la agenda:

clase SharedPreferences

Este proyecto lo puede descargar en un zip desde este enlace: proyecto014.zip

Problema propuesto

  1. Realizar un programa que genere un número aleatorio entre 1 y 50, pedir que el operador lo adivine, informar si ganó o si el número es mayor o menor al ingresado. Cuando el operador lo adivine incrementar en uno el puntaje de juego. Cada vez que se ingrese a la aplicación mostrar el puntaje actual, es decir recordar el puntaje en un archivo de preferencias.

    La interfaz visual de la aplicación a desarrollar es:

    clase SharedPreferences

    Y en tiempo de ejecución debe ser:

    clase SharedPreferences

    Este proyecto lo puede descargar en un zip desde este enlace: proyecto015.zip