Realm (parte 2)

Standard

Hola a todos, buenas tardes.

Después de algunos contratiempos, estamos de regreso para terminar el seguimiento de Realm. Hoy nos enfocaremos en darle funcionalidad a una pequeña aplicación de captura de algunos datos en Android (les adelanto que voy iniciando en el desarrollo con Android, por si ven algún horror en mi codificación, tengan piedad xD).

  • Instalación y Configuración

La instalación de Realm en Android es bastante simple, ahora que Android Studio tiene como default el uso de Gradle con Maven, lo único que tenemos que hacer, es agregar la siguiente linea al archivo “build.gradle” de nuestra aplicación y sincronizar los archivos. Una vez hecho esto, todas las dependencias que necesitamos para usar Realm, se configurarán en nuestro proyecto.

compile 'io.realm:realm-android:0.82.1'
  •   Aplicación de prueba

Ahora que tenemos todo listo para usar Realm, crearemos una pequeña aplicación con dos vistas; Una de las vistas sera para una captura de información básica y la siguiente vista sera solo para listar nuestras capturas.

realm view1 realm view2.1

 

Ahora que tenemos nuestras vista, nos enfocaremos en la funcionalidad. Como primer paso necesitamos tener una instancia que nos permita utilizar Realm en la aplicación. En este caso estoy manejando una instancia por vista. Declarando una propiedad global de Realm.

private Realm realm;

Y en los métodos onCreate de cada vista haremos lo siguiente:

RealmConfiguration config = new RealmConfiguration.Builder(this.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS))
                .build();
realm = Realm.getInstance(config);

Si no usaremos un dispositivo físico, y solo lo ejecutaremos desde nuestro emulador, basta con ejecutar la siguiente linea para poder usar nuestro Realm.

realm = Realm.getInstance(this);

Con estas lineas aseguramos que Realm cree nuestra base de datos y esté accesible para su uso. El nombre por default de un Realm es default.real; Si queremos especificar un nombre personalizado, lo hacemos de la siguiente manera.

RealmConfiguration config = new RealmConfiguration(context).setName("nombrepersonalizado.realm").build();
Realm realm = Realm.getInstance(config);

Ya tenemos acceso a nuestro Realm, podemos leer e insertar información. Si tenemos modelos que usar, los cuales hasta el momento no hemos creado y es nuestro siguiente paso. Para esta aplicación en particular crearemos dos modelos simples, pero que van a estar relacionados. A uno lo llamaremos Employee y otro sera Position.

Employee.java Position.java
public class Employee extends RealmObject{
 
    @PrimaryKey
    private int id;
 
    private String name;
    private int age;
    private Position position;
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public Position getPosition() {
        return position;
    }
 
    public void setPosition(Position position) {
        this.position = position;
    }
}
public class Position extends RealmObject {
 
    @PrimaryKey
    private int id;
 
    private String positionName;
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getPositionName() {
        return positionName;
    }
 
    public void setPositionName(String positionName) {
        this.positionName = positionName;
    }
}

En cada una especificamos una llave primaria del tipo entero, y en este caso tienen una relación Uno a Uno, que solo especificamos al momento de asignar una propiedad del tipo Position en nuestro modelo de Employee, esto sera suficiente siempre y cuando nuestras clases extiendan de la clase RealmObject.

Ya que tenemos nuestros modelos, hay que crear algunos registros en el modelo de Position, ya que serán necesarias para popular nuestro spinner y capturar empleados, lo cual haremos de la siguiente manera.

private void loadPositions(){
    RealmResults<Position> positions = realm.where(Position.class).findAll();
    if(positions.size()==0){
        for(int i=1; i<=5; i++){
            realm.beginTransaction();
            Position position = realm.createObject(Position.class);
            position.setId(i);
            position.setPositionName("Posición " + i);
            realm.commitTransaction();
            spinnerList.add(position.getId() + " - " +position.getPositionName());
        }
    }else{
        for(Position position : positions){
            spinnerList.add(position.getId() + "-" +position.getPositionName());
        }
    }
}

Primero hacemos una consulta al modelo de Position y obtenemos todos los posibles registros que pueda tener. Validamos si hay algún registro y en el caso de no existir ninguno, insertamos 5 nuevos registros; para insertar un nuevo registro en nuestro modelo, el primer paso sera iniciar una transacción; seguimos creando un objeto del modelo en donde haremos las inserciones; lo siguiente sera asignar los valores necesarios para el nuevo registro; por ultimo damos un commit a la transacción y con esto nuestro registro quedara guardado.

realm.beginTransaction();
Position position = realm.createObject(Position.class);
position.setId(i);
position.setPositionName("Posición " + i);
realm.commitTransaction();

En el caso de que ya existan registros solo usaremos los registros que nos regresó la consulta y los asignaremos a la lista que usaremos para nuestro spinner.

for(Position position : positions){
    spinnerList.add(position.getId() + "-" +position.getPositionName());
}

Hay un detalle que no hemos abordado que tiene que ver con las llaves primarias. El detalle es que Realm no tiene un manejo de lo que usaríamos comúnmente como un valor autoincremental, por lo tanto los valores de nuestra llave los tendremos que controlar nosotros. En este caso se resolvió usando una función que nos regrese el valor máximo usado en la entidad y con esto evitaremos que nuestra llave se repita.

    private int getTableId(Class clazz){
        Long tableId = realm.where(clazz).maximumInt("id");
        if(tableId==0){
            tableId=1L;
        }else{
            tableId++;
        }
        return tableId.intValue();
    }

Lo único fuera de lo normal al momento de obtener los datos para guardar el nuevo empleado es que buscaremos el registro relacionado con la posición que seleccionemos. Dado que al momento de agregarlo al spinner lo agregamos como texto, hay que extraer el id que le adjuntamos después del “-“. Una vez que obtengamos ese id podemos realizar una consulta buscando ese registro y guardar el nuevo empleado.

    public void onSave(View view){
 
        EditText textName = (EditText) findViewById(R.id.name_edit);
        EditText textAge = (EditText) findViewById(R.id.age_numeric);
        Spinner spinner = (Spinner) findViewById(R.id.position_spinner);
        String positionSelected = (String) spinner.getSelectedItem();
        String[] positionSplit = positionSelected.split("-");
        int positionId = Integer.parseInt(positionSplit[0].trim());
        Log.i("ITEM_SELECTED", positionSplit[0].trim());
        Integer tableId = getTableId(Employee.class);
        Log.i("TABLE ID", tableId.toString());
        try{
            realm.beginTransaction();
 
            Employee employee = realm.createObject(Employee.class);
            employee.setId(tableId);
            employee.setName(textName.getText().toString());
            employee.setAge(Integer.parseInt(textAge.getText().toString()));
 
            Position position = realm.where(Position.class).equalTo("id", positionId).findFirst();
            employee.setPosition(position);
 
            realm.commitTransaction();
        }catch(RealmError e){
            realm.cancelTransaction();
            Log.e("REALMERROR", e.getMessage());
        }
 
    }

Con esto ya podremos guardar nuevos registros de empleados para nuestra aplicación. Utilizamos una sentencia try->catch para cancelar la transacción en caso de que por algún motivo tengamos un problema.

En el layout para listar nuestros datos, lo único que haremos es realizar una consulta a nuestro modelo de <i>Employee</i> y de ahi obtendremos toda la información que necesitamos para listar en nuestra vista.

private void getDataFromRealm(){
    RealmQuery<Employee> query = realm.where(Employee.class);

    RealmResults<Employee> employees = query.findAll();

    for (Employee employee : employees){
        String employeeString = employee.getId() + " - " + employee.getName() + " - " + employee.getPosition().getPositionName();
        listItems.add("Empleado: " + employeeString);
    }
}

Y así de fácil y sin tantas complicaciones usamos Realm en un dispositivo móvil. Aun tiene mucho trabajo que realizar, pero sin duda es una opción para los desarrolladores de móviles que buscan una alternativa viable a SQLite o Coredata.

Este tema tiene mucho para dar, pero le daremos un descanso para no aburrirlos. Para la próxima si desarrollamos otra mini aplicación utilizando Realm, lo haremos con un video tutorial para facilitarnos la existencia y hacer el post más dinámico y sin que tengan que leer tanto.

Les dejo un saludo y que tengan un buen fin de semana

El proyecto se los dejo en un repositorio de github:

https://github.com/unDeveloper/RealmTest.git

Referencias:

https://realm.io/

https://realm.io/docs/java/latest/

 

Leave a Reply

Your email address will not be published. Required fields are marked *