Android
Rike
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();
}
});