수색…


소개

Realm Mobile Database는 SQLite의 대안입니다. 영역 모바일 데이터베이스는 ORM보다 훨씬 빠르며 종종 원시 SQLite보다 빠릅니다.

은혜

오프라인 기능, 빠른 쿼리, 안전한 스레딩, 교차 플랫폼 응용 프로그램, 암호화, 반응 아키텍처.

비고

영역을 사용할 때는 스레드간에 RealmObjects, RealmResults 및 Realm 인스턴스를 전달하면 안됩니다. 특정 스레드에 대한 쿼리가 필요한 경우 해당 스레드에서 영역 인스턴스를 엽니 다. 스레드가 종료되면 영역을 닫아야합니다.

법적 참고 사항 : 귀하는 소프트웨어에 수출 제한 대상이 될 수있는 암호화 기능이 포함되어있을 수 있으며 귀하는 쿠바,이란, 북쪽을 포함하여 미국 수출 제한이나 수출 금지 대상 국가에 있지 않음 을 진술하고 보증합니다 수단, 시리아 또는 크림 지역에 거주 하고 있으며 귀하가 거부당한 사람, 확인되지 않은 당사자 또는 제한된 단체와 제휴 한 상무부 목록에 있지 않음을 확인합니다.

프로젝트에 영역 추가하기

프로젝트 레벨 build.gradle 파일에 다음 종속성을 추가하십시오.

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

수준 build.gradle 파일 상단에 다음 권한을 추가합니다.

apply plugin: 'realm-android'

gradle sync를 완료하면 이제 Realm이 프로젝트에 종속되어 추가되었습니다!

Realm은 사용하기 전에 2.0.0부터 초기 호출이 필요합니다. Application 클래스 나 첫 번째 Activity의 onCreate 메소드에서이 작업을 수행 할 수 있습니다.

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

영역 모델

영역 모델RealmObject 기본 클래스를 확장해야하며 기본 데이터베이스의 스키마를 정의합니다.

지원되는 필드 유형은 boolean , byte , short , int , long , float , double , String , Date , byte[] , 다른 RealmObject 링크 및 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
}

RealmObject에 새 필드를 추가하거나 제거하거나 새 RealmObject 클래스를 추가하거나 기존 RealmObject 클래스를 삭제하면 마이그레이션 이 필요합니다. 당신도 설정할 수 있습니다 deleteIfMigrationNeeded() 당신에 RealmConfiguration.Builder , 또는 필요한 마이그레이션을 정의합니다. 마이그레이션은 추가 (또는 삭제) 할 때 필요 @Required , 또는 @Index , 또는 @PrimaryKey 주석을.

관계는 수동으로 설정해야하며 기본 키를 기반으로 자동으로 설정되지 않습니다.

0.88.0부터 RealmObject 클래스에서 private 필드 / getters / setter 대신 public 필드를 사용할 수도 있습니다.

또한 클래스에 @RealmClass 주석을 추가 한 경우 RealmObject 를 확장하는 대신 RealmModel 을 구현할 수도 있습니다.

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

이 경우 person.deleteFromRealm() 또는 person.addChangeListener() 와 같은 메소드가 RealmObject.deleteFromRealm(person)RealmObject.addChangeListener(person) 로 대체됩니다.

제한 사항은 a로한다는 것이다 RealmObjectRealmObject 연장 될 수 있으며, 대한 지원이없는 final , volatiletransient 필드.

관리되는 RealmObject 클래스는 트랜잭션에서만 수정할 수 있어야합니다. 관리되는 RealmObject는 스레드간에 전달 될 수 없습니다.

프리미티브 목록 (RealmList )

영역은 현재 프리미티브 목록 저장을 지원하지 않습니다. 할 일 목록 ( GitHub issue # 575 )에 있지만 그 동안 해결 방법이 있습니다.

기본 유형에 대한 새로운 클래스를 작성하십시오.이 클래스는 Integer를 사용하지만 저장하려는 모든 항목에 대해 변경합니다.

public class RealmInteger extends RealmObject {
    private int val;

    public RealmInteger() {
    }

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

    // Getters and setters
}

이제 이것을 RealmObject 에서 사용할 수 있습니다.

public class MainObject extends RealmObject {

    private String name;
    private RealmList<RealmInteger> ints;

    // Getters and setters
}

GSON 을 사용하여 RealmObject 를 채우는 경우 사용자 정의 유형 어댑터를 추가해야합니다.

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();

자원을 사용하여 시험 사용

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 with resources는 KITKAT (minSDK 19)에서만 사용할 수 있습니다.

정렬 된 쿼리

findAll() 을 사용하는 대신 쿼리를 정렬하려면 findAllSorted() 를 사용해야합니다.

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

노트 :

sort()sort() 된 완전히 새로운 RealmResults를 반환하지만이 RealmResults에 대한 업데이트로 재설정됩니다. 당신이 사용하는 경우 sort() , 당신은 항상 다시 정렬해야 당신의 그것을 RealmChangeListener , 제거 RealmChangeListener 이전에서 RealmResults 하고 반환 된 새에 추가 RealmResults . 아직로드되지 않은 비동기 쿼리에서 반환 된 RealmResults 에서 sort() 를 사용하면 실패합니다.

findAllSorted() 는 업데이트 된 경우에도 항상 필드에 의해 정렬 된 결과를 반환합니다. findAllSorted() 를 사용하는 것이 좋습니다.

비동기 쿼리

모든 동기 쿼리 메서드 (예 : findAll() 또는 findAllSorted() )에는 비동기 카운터 파트 ( findAllAsync() / findAllSortedAsync() )가 있습니다.

비동기 쿼리는 RealmResults 의 평가를 다른 스레드로 오프로드합니다. 현재 스레드에서 이러한 결과를 수신하려면 현재 스레드가 루퍼 스레드 여야합니다 (읽기 : 비동기 조회는 일반적으로 UI 스레드에서만 작동합니다).

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);

RxJava에서 영역 사용

쿼리의 경우 Realm은 realmResults.asObservable() 메서드를 제공합니다. 루퍼 스레드 (일반적으로 UI 스레드)에서만 결과를 관찰 할 수 있습니다.

이 작업을 수행하려면 구성에 다음 내용이 포함되어야합니다.

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

그런 다음 결과를 관찰 가능 항목으로 사용할 수 있습니다.

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

비동기 쿼리의 경우 isLoaded() 하여 결과를 필터링하여 쿼리가 실행될 때만 이벤트를 수신하도록해야합니다. 이 filter() 는 동기 쿼리에 필요하지 않습니다. isLoaded() 항상 동기화 쿼리에서 true 를 반환 true .

    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));

쓰기의 경우 executeTransactionAsync() 메소드를 사용하거나 백그라운드 스레드에서 Realm 인스턴스를 열고 트랜잭션을 동 기적으로 실행 한 다음 Realm 인스턴스를 닫아야합니다.

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

기본 사용법

인스턴스 설정

렐름을 사용하려면 먼저 렐름의 인스턴스를 얻어야합니다. 각 Realm 인스턴스는 디스크의 파일에 매핑됩니다. 인스턴스를 가져 오는 가장 기본적인 방법은 다음과 같습니다.

// 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();

Realm.getInstance() 메소드는 작성되지 않은 경우 데이터베이스 파일을 작성하고, 그렇지 않으면 파일을 엽니 다. RealmConfiguration 객체는 inMemory() 데이터베이스, Realm 파일 이름, 마이그레이션이 필요하면 영역을 지워야하는지 여부, 초기 데이터 등 Realm이 작성되는 방식의 모든 측면을 제어합니다.

Realm.getInstance() 에 대한 호출은 참조 횟수 (각 호출은 카운터 증가)이며 realm.close() 가 호출되면 카운터가 감소합니다.

인스턴스 닫기

백그라운드 스레드에서는 더 이상 사용되지 않는 영역 인스턴스를 닫는 것이 매우 중요 합니다 (예 : 트랜잭션 완료 및 스레드 실행 종료). 백그라운드 스레드에서 모든 Realm 인스턴스를 닫지 못하면 버전 피닝이 발생하고 파일 크기가 크게 커질 수 있습니다.

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

API 레벨 19 이상에서는이 코드를 다음과 같이 바꿀 수 있습니다.

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

모델

다음 단계는 모델을 만드는 것입니다. 여기서 "모델이란 무엇입니까?"라는 질문을 할 수 있습니다. 모델은 데이터베이스에 저장되는 객체의 속성을 정의하는 구조입니다. 예를 들어, 다음에서는 책을 모델링합니다.

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;
    }
}

모델은 RealmObject 클래스를 확장해야합니다. 기본 키는 @PrimaryKey 주석에 의해 지정됩니다. 1 차 키는 널 (NULL)이 될 수 있지만, 하나의 요소 만이 null )을 기본 키로 가질 수 있습니다. 또한 디스크에 저장하지 않아야하는 필드에 @Ignore 주석을 사용할 수 있습니다.

@Ignore
private String isbn;

데이터 삽입 또는 업데이트

Book 객체를 Realm 데이터베이스 인스턴스에 저장하려면 먼저 모델의 인스턴스를 만든 다음 copyToRealm 메소드를 통해 데이터베이스에 저장합니다. 생성 또는 업데이트하려면 copyToRealmOrUpdate 를 사용할 수 있습니다. (더 빠른 대안은 새로 추가 된 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);
    }
});

데이터에 대한 모든 변경 사항은 트랜잭션에서 발생해야합니다. 객체를 만드는 또 다른 방법은 다음 패턴을 사용하는 것입니다.

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

데이터베이스 쿼리하기

  • 모든 도서 :

    RealmResults<Book> results = realm.where(Book.class).findAll();
    
  • 10보다 큰 ID를 가진 모든 책 :

    RealmResults<Book> results = realm.where(Book.class)
                                      .greaterThan("id", 10)
                                      .findAll();
    
  • 'Taylor Swift' 또는 '%Peter%' 저서들 :

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

객체 삭제하기

예를 들어 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
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow