Gestire i dati con Realm

7 giugno 2017

Tipicamente, la gestione dei dati di un’app Android si basa su Sqlite, un DBMS relazionale già integrato nel sistema, capace di salvare un intero database relazionale in un unico file. Il suo funzionamento è efficiente ma richiede le consuete conversioni tra modello ad oggetti e relazionale, che possono risultare piuttosto ripetitive. Realm, la libreria di cui tratta questa lezione, offre una gestione dei dati interamente ad oggetti. Non si tratta nè di un O/RM nè di un wrapper per Sqlite, bensì di un meccanismo di persistenza totalmente originale.

La versione per Android di questo progetto è solo una delle tante offerte disponibili, esistenti per tutte le più diffuse tecnologie: Xamarin, Swift ma anche mobile ibrido e Node.js.

Realm in un progetto Android Studio

Il 2017 ha visto nei primi mesi la pubblicazione della terza major release di Realm Java. Per utilizzarne le funzionalità, è necessario che il proprio ambiente di lavoro soddisfi i seguenti prerequisiti:

  • Android Studio 1.5.1 o versioni successive;
  • JDK di versione maggiore o uguale a 7;
  • Android SDK recente (livello minimo di API: 9, ovvero Android 2.3).

L’integrazione di Realm in un progetto Android Studio offre la comoda forma di plugin. Pertanto, procederemo in due passi:

  • nel file build.gradle del progetto inseriremo la direttiva classpath:
    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath "io.realm:realm-gradle-plugin:3.1.0"
        }
    }
    
  • nel file build.gradle dell’applicazione richiamiamo il plugin con la seguente direttiva a inizio file:
    apply plugin: 'realm-android'
    

Al termine di tali modifiche sarà necessario sincronizzare nuovamente il progetto con i file di configurazione di Android Studio: l’IDE, comunque, ce lo ricorderà prontamente.

Inizializzazione di Realm

Prima di poter utilizzare Realm è necessario inizializzarlo, invocando il metodo statico init della classe Realm. Per evitare di ripetere questa fase (ed altre analoghe) continuamente, è conveniente estendere la classe Application nel seguente modo:

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        Realm.init(this);
        RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().build();
        Realm.setDefaultConfiguration(realmConfiguration);
    }
}

e riportare poi il nome di questa classe nell’attributo name del nodo <application>, all’interno del file AndroidManifest.xml:

 <application
        android:name=".MyApplication"
		... >

In fase di inizializzazione, volendo, si può provvedere alla cancellazione del vecchio archivio con:

Realm.deleteRealm(realmConfiguration);

Prime operazioni con Realm

La classe MyApplication mette a disposizione un’istanza di Realm ovunque serva nell’applicazione. Per utilizzarla nell’Activity, converrà ottenere un riferimento ad un oggetto Realm nel metodo onCreate (da salvare come membro della classe). L’oggetto verrà racchiuso nel metodo onDestroy:

    private Realm realm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ..
		..
		realm= Realm.getDefaultInstance();
		..
		..
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        realm.close();
    }

I dati verranno salvati in Realm mediante oggetti che diventeranno automaticamente persistenti. estendendo la classe RealmObject. Creiamo, ad esempio, una classe Libro. Questa operazione corrisponderà alla definizione di una tabella in un database:

public class Libro extends RealmObject{

    private String autore;
    private String titolo;
    private int numeroPagine;
    private int annoPubblicazione;

	/*
	 *	OMISSIS: getter, setter e altri metodi
	 */
}

Per inserire un nuovo oggetto all’interno del database, dovremo semplicemente creare un oggetto di questa classe ed inserirvi i dati:

        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                Libro l = realm.createObject(Libro.class);
                l.setAutore("Alessandro Manzoni");
                l.setTitolo("I Promessi Sposi");
                l.setNumeroPagine(600);
                l.setAnnoPubblicazione(1827);
            }
        });

Si noti che l’oggetto è stato generato con il metodo createObject e non con il consueto operatore new. Le operazioni di modifica andranno eseguite all’interno di una Transaction, che può essere sviluppata con un oggetto di classe anonima come si vede nell’esempio precedente.

Eseguire query

Anche per le query l’approccio è totalmente ad oggetti. Il metodo where recupererà gli oggetti dalla classe specificata ed il suo risultato potrà essere trattato con filtri tramite altri metodi specifici. Al termine della configurazione della selezione, si invocherà il metodo findAll per il recupero di tutti i risultati corrispondenti, findAllSorted per ottenere un risultato ordinato o findFirst qualora si voglia solo il primo risultato. Ecco alcuni esempi:

  • tutti gli oggetti appartenenti alla classe Libro:
    RealmResults<Libro> results = realm.where(Libro.class).findAll()
    
  • tutti gli oggetti appartenenti alla classe Libro ordinati in senso decrescente in base al valore del membro annoPubblicazione:
    RealmResults<Libro> results = realm.where(Libro.class).findAllSorted("annoPubblicazione", Sort.DESCENDING)
    
  • tutte le opere pubblicate tra il 1940 ed il 1960:
    RealmResults<Libro> results = realm.where(Libro.class).between("annoPubblicazione",1940, 1960).findAll()
    
  • tutte le opere successive all’anno 2000:
    RealmResults<Libro> results = realm.where(Libro.class).greaterThan("annoPubblicazione",2000).findAll()
    

Oltre ai metodi di filtering appena visti (ed altri ancora consultabili nella documentazione ufficiale) esistono costrutti logici che permettono di formulare interrogazioni più avanzate, come ad esempio beginGroup e endGroup per racchiudere delle valutazioni (una sorta di parentesi), not per negare una condizione o or per l’omonima operazione logica. Ad esempio, cerchiamo i libri che neghino la condizione per cui l’anno di pubblicazione sia inferiore al 1970 o il numero di pagine sia superiore a 400:

RealmResults<Libro> results =realm.where(Libro.class)
				.not()
				.beginGroup()
                .lessThan("annoPubblicazione",1970)
                .or()
                .greaterThan("numeroPagine",400)
                .endGroup()
                .findAll();

La classe RealmResults costituisce il set di risultati della query ed è una Collection iterabile, e pertanto accessibile con i consueti metodi offerti dal linguaggio Java: ciclo for, accesso in base alla posizione e Iterator.

Cancellazione e modifica

I risultati di una query possono essere oggetto di cancellazione. Ad esempio, ottenuto un oggetto RealmResults si può procedere alla cancellazione complessiva del contenuto con deleteAllFromRealm o, in alternativa, del primo o ultimo valore, rispettivamente, con deleteFirstFromRealm e deleteLastFromRealm. Per la cancellazione puntuale di un elemento, lo si può selezionare in base alla posizione, ordinandone l’eliminazione:

RealmResults<Libro> results = ....

// selezione e distruzione del quarto elemento
Libro daCancellare=results.get(3);
daCancellare.deleteFromRealm();

Gli oggetti che vengono recuperati possono anche essere modificati all’interno di una transazione. In alternativa, possiamo inserire in un realm (l’equivalente di un database, secondo questo paradigma) un oggetto “non gestito”, ossia un oggetto creato in Java con la normale procedura di istanziazione, utilizzando il metodo copyToRealm. Inoltre, sarà possibile ricevere in automatico informazioni sulle modifiche subite da oggetti referenziati in una collection RealmResults utilizzando un listener di classe RealmChangeListener:

RealmResults<Libro> results = ....

results.addChangeListener(new RealmChangeListener<RealmResults<Libro>>() {
    @Override
    public void onChange(RealmResults<Libro> r) {
        
		/*
		 *  r costituisce il set aggiornato di risultati
		 */
    }
});

Appendice

Quanto visto in questa lezione può essere sufficiente per utilizzare Realm come sistema di persistenza della propria app, sebbene lo studio può ulteriomente essere approfondito. Elementi interessanti di studio sono, ad esempio, la libreria di Adapter messa a disposizione per integrare i risultati delle query con AdapterView tradizionali e RecyclerView, nonchè la possibilità di svolgere query asincrone per non penalizzare le prestazioni dell’interfaccia utente.

Tutte le lezioni

1 ... 32 33 34 ... 82

Se vuoi aggiornamenti su Gestire i dati con Realm inserisci la tua e-mail nel box qui sotto:
Tags:
 
X
Se vuoi aggiornamenti su Gestire i dati con Realm

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy