Модель :

public class Dog extends RealmObject {
  @PrimaryKey
  public String id = UUID.randomUUID().toString();
  ... other random String attributes
  public Dog mother;
}

Деятельности:

public class CustomActivity extends AppCompatActivity {
  private Realm realm;
  private Dog dog = new Dog();

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

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

  private void setMother(int id) {
   dog.mother = realm.where(Dog.class).equalTo(ID, id).findFirst();
  }

  private void saveDog() {
   realm.executeTransactionAsync(new Realm.Transaction() {
      @Override
      public void execute(Realm realm) {
        realm.copyToRealmOrUpdate(dog);
      }
    });
  }

}

Когда я запускаю этот код, он дает мне эту ошибку:

Objects which belong to Realm instances in other threads cannot be copied into this Realm instance.

Единственный способ заставить его работать, это использовать realm.copyFromRealm (), но весь объект копируется, и я этого не хочу.

Должен ли я сохранить идентификатор матери в одиночку и запрашивать ее у матери, где бы она мне не понадобилась, в моем приложении?

Есть ли способ достичь того, что я пытаюсь сделать, не копируя весь объект?


РЕДАКТИРОВАТЬ:

Первоначально я думал, что весь объект был скопирован с помощью realm.copyFromRealm () из-за того, как он выглядит в браузере областей.
Я только что проверил, чтобы обновить поле в dog.mother, и он обновляет связанный объект, что означает, что это не копия.
Я до сих пор не знаю, является ли это лучшим или правильным способом достижения того, что я пытаюсь сделать, но он делает то, что хотел.

0
seb 28 Май 2017 в 20:30

2 ответа

Лучший ответ
  private Realm realm;    

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    realm = Realm.getDefaultInstance(); //<--- this is on ui thread

realm.executeTransactionAsync(new Realm.Transaction() {
  @Override
  public void execute(Realm realm) {
    realm.copyToRealmOrUpdate(dog);  // <-- this is on background thread
  //...


private void setMother(int id) {
   dog.mother = realm.where(Dog.class).equalTo(ID, id).findFirst(); // <-- uses UI-thread Realm stored as field

Поэтому, если вы используете setMother() в фоновом потоке, вы получите доступ к области потока пользовательского интерфейса и вызовет исключение IllegalStateException.

Вам нужно передать Realm для данного потока в метод.

  private void setMother(Realm realm, Dog dog, int id) {
   dog.mother = realm.where(Dog.class).equalTo(ID, id).findFirst();
  }

  private void saveDog() {
   realm.executeTransactionAsync(new Realm.Transaction() {
      @Override
      public void execute(Realm realm) {
        Dog _dog = realm.copyToRealmOrUpdate(dog);
        setMother(realm, _dog, id);
      }
    });
1
EpicPandaForce 29 Май 2017 в 14:20

Исключение происходит из-за того, что вы создаете объект Dog в потоке пользовательского интерфейса, а затем передаете его асинхронному рабочему потоку, но это означает, что вы также передали ссылку на mother, что недопустимо. Вместо этого вам нужно выполнить настройку в асинхронном методе следующим образом:

private void saveDog() {
    realm.executeTransactionAsync(new Realm.Transaction() {
      @Override
      public void execute(Realm realm) {
        // This will give you mother reference on the correct thread
        setMother(motherId, dog);
        realm.copyToRealmOrUpdate(dog);
      }
    });
}
1
Christian Melchior 29 Май 2017 в 09:38