Sök…


Introduktion

Realm Mobile Database är ett alternativ till SQLite. Realm Mobile Database är mycket snabbare än en ORM, och ofta snabbare än rå SQLite.

fördelar

Offline-funktionalitet, Snabbfrågor, säker trådning, plattformsappar, kryptering, reaktiv arkitektur.

Anmärkningar

När du använder Realm måste du komma ihåg att du inte får passera RealmObjects, RealmResults och Realm-instanser mellan trådar. Om du behöver en fråga på en viss tråd öppnar du en Realm-instans på den tråden. När tråden avslutas bör du stänga riket.

RÄTTSLIG ANMÄRKNING : Du förstår att programvaran kan innehålla kryptografiska funktioner som kan vara föremål för exportbegränsningar, och du föreställer och garanterar att du inte är belägen i ett land som omfattas av USA: s exportbegränsning eller embargo, inklusive Kuba, Iran, North Korea, Sudan, Syrien eller Krim-regionen , och att du inte är med på listan över handelsdepartementet med nekade personer, overifierade parter eller är ansluten till en begränsad enhet.

Lägga till Realm i ditt projekt

Lägg till följande beroendet till projektnivå build.gradle fil.

dependencies {
    classpath "io.realm:realm-gradle-plugin:3.1.2"
}

Lägg till följande högst upp på appens nivå build.gradle fil.

apply plugin: 'realm-android'

Slutför en gradsynkronisering så har du nu Realm som ett beroende till ditt projekt!

Realm kräver ett första samtal sedan 2.0.0 innan du använder det. Du kan göra detta i din Application eller i din första aktivitets onCreate metod.

Realm.init(this); // added in Realm 2.0.0
Realm.setDefaultConfiguration(new RealmConfiguration.Builder().build());

Realmodeller

Realm-modeller måste utöka RealmObject basklassen, de definierar schemat för den underliggande databasen.

Fälttyper som stöds är boolean , byte , short , int , long , float , double , String , Date , byte[] , länkar till andra RealmObject s och RealmList<T extends RealmModel> .

public class Person extends RealmObject {
    @PrimaryKey //primary key is also implicitly an @Index 
                //it is required for `copyToRealmOrUpdate()` to update the object.
    private long id;

    @Index //index makes queries faster on this field
    @Required //prevents `null` value from being inserted
    private String name; 

    private RealmList<Dog> dogs; //->many relationship to Dog

    private Person spouse; //->one relationship to Person

    @Ignore
    private Calendar birthday; //calendars are not supported but can be ignored

    // getters, setters
}

Om du lägger till (eller tar bort) ett nytt fält till din RealmObject (eller lägger till en ny RealmObject-klass eller tar bort ett befintligt) kommer en migrering att behövas. Du kan antingen ställa deleteIfMigrationNeeded() i din RealmConfiguration.Builder eller definiera den nödvändiga migreringen. Migrering krävs också när du lägger till (eller tar bort) @Required , eller @Index eller @PrimaryKey kommentar.

Relationer måste ställas in manuellt, de är INTE automatiska baserade på primära nycklar.

Sedan 0.88.0 är det också möjligt att använda offentliga fält istället för privata fält / getters / setters i RealmObject-klasser.

Det är också möjligt att implementera RealmModel istället för att utöka RealmObject , om klassen också kommenteras med @RealmClass .

@RealmClass
public class Person implements RealmModel {
    // ...
}

I så fall person.deleteFromRealm() metoder som person.deleteFromRealm() eller person.addChangeListener() med RealmObject.deleteFromRealm(person) och RealmObject.addChangeListener(person) .

Begränsningarna är att med en RealmObject kan bara RealmObject utökas och det finns inget stöd för final , volatile och transient fält.

Det är viktigt att en hanterad klass RealmObject endast kan ändras i en transaktion. Ett hanterat RealmObject kan inte skickas mellan trådar.

Lista över primitiv (RealmList )

Realm stöder för närvarande inte lagring av en lista över primitiv. Det finns på deras todo-lista ( GitHub-nummer 575 ), men för tiden är det en lösning.

Skapa en ny klass för din primitiva typ, den här använder heltal, men ändra den för vad du vill lagra.

public class RealmInteger extends RealmObject {
    private int val;

    public RealmInteger() {
    }

    public RealmInteger(int val) {
        this.val = val;
    }

    // Getters and setters
}

Du kan nu använda detta i ditt RealmObject .

public class MainObject extends RealmObject {

    private String name;
    private RealmList<RealmInteger> ints;

    // Getters and setters
}

Om du använder GSON att fylla din RealmObject , måste du lägga till en anpassad adapter.

Type token = new TypeToken<RealmList<RealmInteger>>(){}.getType();
Gson gson = new GsonBuilder()
        .setExclusionStrategies(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes f) {
                return f.getDeclaringClass().equals(RealmObject.class);
            }

            @Override
            public boolean shouldSkipClass(Class<?> clazz) {
                return false;
            }
        })
        .registerTypeAdapter(token, new TypeAdapter<RealmList<RealmInteger>>() {

            @Override
            public void write(JsonWriter out, RealmList<RealmInteger> value) throws IOException {
                // Empty
            }

            @Override
            public RealmList<RealmInteger> read(JsonReader in) throws IOException {
                RealmList<RealmInteger> list = new RealmList<RealmInteger>();
                in.beginArray();
                while (in.hasNext()) {
                    list.add(new RealmInteger(in.nextInt()));
                }
                in.endArray();
                return list;
            }
        })
        .create();

prova-med-resurser

try (Realm realm = Realm.getDefaultInstance()) {
    realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                //whatever Transaction that has to be done
            }
    });
    //No need to close realm in try-with-resources
}

Try med resurser kan endast användas från KITKAT (minSDK 19)

Sorterade frågor

För att sortera en fråga, i stället för att använda findAll() , bör du använda findAllSorted() .

RealmResults<SomeObject> results = realm.where(SomeObject.class)
                                            .findAllSorted("sortField", Sort.ASCENDING);

Notera:

sort() returnerar en helt ny RealmResults som sorteras, men en uppdatering till RealmResults återställer den. Om du använder sort() bör du alltid sortera det igen i din RealmChangeListener , ta bort RealmChangeListener från föregående RealmResults och lägga till den i de returnerade nya RealmResults . Att använda sort() på en RealmResults returneras av en asyncfråga som ännu inte är inläst kommer att misslyckas.

findAllSorted() kommer alltid att returnera resultaten sorterade efter fältet, även om det uppdateras. Det rekommenderas att använda findAllSorted() .

Asyncfrågor

Varje synkron frågemetod (som findAll() eller findAllSorted() ) har en asynkron motsvarighet ( findAllAsync() / findAllSortedAsync() ).

Asynkrona frågor avlägsnar utvärderingen av RealmResults till en annan tråd. För att få dessa resultat på den aktuella tråden måste den aktuella tråden vara en loopertråd (läs: asyncfrågor fungerar vanligtvis bara på UI-tråden).

RealmChangeListener<RealmResults<SomeObject>> realmChangeListener; // field variable

realmChangeListener = new RealmChangeListener<RealmResults<SomeObject>>() {
    @Override
    public void onChange(RealmResults<SomeObject> element) {
        // asyncResults are now loaded
        adapter.updateData(element);
    }
};

RealmResults<SomeObject> asyncResults = realm.where(SomeObject.class).findAllAsync();
asyncResults.addChangeListener(realmChangeListener);

Använda Realm med RxJava

För frågor ger realmResults.asObservable() metoden realmResults.asObservable() . Att observera resultat är endast möjligt på looper-trådar (vanligtvis UI-tråden).

För att detta ska fungera måste din konfiguration innehålla följande

realmConfiguration = new RealmConfiguration.Builder(context)       //
                          .rxFactory(new RealmObservableFactory()) //
                             //...
                          .build();

Efteråt kan du använda dina resultat som observerbara.

Observable<RealmResults<SomeObject>> observable = results.asObservable();

För asynkrona frågor bör du filtrera resultaten efter isLoaded() , så att du får en händelse endast när frågan har körts. Detta filter() behövs inte för synkrona frågor ( isLoaded() returnerar alltid true på synkroniseringsfrågor).

    Subscription subscription = RxTextView.textChanges(editText).switchMap(charSequence -> 
        realm.where(SomeObject.class)
             .contains("searchField", charSequence.toString(), Case.INSENSITIVE)
             .findAllAsync()
             .asObservable())
    .filter(RealmResults::isLoaded) //
    .subscribe(objects -> adapter.updateData(objects));

För skrivningar bör du antingen använda executeTransactionAsync() -metoden eller öppna en Realm-instans på bakgrundstråden, genomföra transaktionen synkront och sedan stänga Realm-instansen.

public Subscription loadObjectsFromNetwork() {
    return objectApi.getObjects()
        .subscribeOn(Schedulers.io())
        .subscribe(response -> {
            try(Realm realmInstance = Realm.getDefaultInstance()) {
                realmInstance.executeTransaction(realm -> realm.insertOrUpdate(response.objects));
            }
        });
}

Grundläggande användning

Ställa in en instans

För att använda Realm måste du först skaffa en instans av den. Varje Realm-instans kartlägger till en fil på disken. Det mest grundläggande sättet att få en instans är enligt följande:

// Create configuration
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(context).build();

// Obtain realm instance
Realm realm = Realm.getInstance(realmConfiguration);
// or
Realm.setDefaultConfiguration(realmConfiguration);
Realm realm = Realm.getDefaultInstance();

Metoden Realm.getInstance() skapar databasfilen om den inte har skapats, annars öppnar filen. RealmConfiguration objektet styr alla aspekter av hur ett rike skapas - oavsett om det är en inMemory() databas, namnet på Realm-filen, om Realm ska rensas om en migration behövs, initial data etc.

Observera att samtal till Realm.getInstance() räknas med referens (varje samtal ökar en räknare) och räknaren minskas när realm.close() anropas.

Stänger en instans

På bakgrundstrådar är det mycket viktigt att stänga Realm-instansen när den inte längre används (till exempel är transaktionen slutförd och trådkörningen slutar). Underlåtenhet att stänga alla Realm-instanser på bakgrundstråd resulterar i fästning av versionen och kan orsaka en stor tillväxt i filstorlek.

Runnable runnable = new Runnable() {
    Realm realm = null;
    try {
        realm = Realm.getDefaultInstance();
        // ...
    } finally {
        if(realm != null) {
            realm.close();
        }
    }
};

new Thread(runnable).start(); // background thread, like `doInBackground()` of AsyncTask

Det är värt att notera att ovanför API-nivå 19 kan du ersätta den här koden med bara detta:

try(Realm realm = Realm.getDefaultInstance()) {
    // ...
}

modeller

Nästa steg skulle vara att skapa dina modeller. Här kan en fråga ställas, "vad är en modell?". En modell är en struktur som definierar egenskaperna hos ett objekt som lagras i databasen. Till exempel i följande modellerar vi en bok.

public class Book extends RealmObject {
 
    // Primary key of this entity
    @PrimaryKey
    private long id;
 
    private String title;

    @Index // faster queries
    private String author;
 
    // Standard getters & setter
    public long getId() {
        return id;
    }
 
    public void setId(long id) {
        this.id = id;
    }
 
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
 
    public String getAuthor() {
        return author;
    }
 
    public void setAuthor(String author) {
        this.author = author;
    }
}

Observera att dina modeller ska utvidga RealmObject-klassen. Primär nyckel anges också av @PrimaryKey kommentarer. Primära nycklar kan vara noll, men endast ett element kan ha null som en primär nyckel. Du kan också använda @Ignore annotationen för fälten som inte ska fortsätta på disken:

@Ignore
private String isbn;

Infoga eller uppdatera data

För att lagra ett bokobjekt i din Realm-databasinstans kan du först skapa en instans av din modell och sedan lagra den i databasen via copyToRealm metoden. För att skapa eller uppdatera kan du använda copyToRealmOrUpdate . (Ett snabbare alternativ är det nyligen tillagda insertOrUpdate() ).

// Creating an instance of the model
Book book = new Book();
book.setId(1);
book.setTitle("Walking on air");
book.setAuthor("Taylor Swift")

// Store to the database
realm.executeTransaction(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        realm.insertOrUpdate(book);
    }
});

Observera att alla ändringar av data måste ske i en transaktion. Ett annat sätt att skapa ett objekt använder följande mönster:

Book book = realm.createObject(Book.class, primaryKey);
...

Fråga efter databasen

  • Alla böcker:

    RealmResults<Book> results = realm.where(Book.class).findAll();
    
  • Alla böcker med id större än 10:

    RealmResults<Book> results = realm.where(Book.class)
                                      .greaterThan("id", 10)
                                      .findAll();
    
  • Böcker av 'Taylor Swift' eller '%Peter%' :

    RealmResults<Book> results = realm.where(Book.class)
                                      .beginGroup()
                                          .equalTo("author", "Taylor Swift")
                                          .or()
                                          .contains("author", "Peter")
                                      .endGroup().findAll();
    

Radera ett objekt

Vi vill till exempel ta bort alla böcker av Taylor Swift:

// Start of transaction
realm.executeTransaction(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        // First Step: Query all Taylor Swift books
        RealmResults<Book> results = ...
        
        // Second Step: Delete elements in Realm
        results.deleteAllFromRealm();
    }
});


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow