Как можно избежать ошибки "Попытка вызвать виртуальный метод" из логического объекта io.realm.ProxyState.isUnderConstruction () 'для ссылки на пустой объект в Realm.io " - PullRequest
0 голосов
/ 06 марта 2019

ОБНОВЛЕНИЕ:

На данный момент я не могу создавать какие-либо новые объекты на основе Царства.Каждый из них дает сбой с одной и той же ошибкой, независимо от того, очищаю ли я, перестраиваю и т. Д. Чтобы проверить это, я создал новый класс «Образец»:

package com.reddragon.intouch.model;

import java.util.UUID;

import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;

public class Sample extends RealmObject {
    @PrimaryKey
    private String id;
    private String sampleField;

    public Sample() {
        this(UUID.randomUUID().toString());
    }
    private Sample(String id) {
        this.id=id;
    }
    public String getId(){
        return id;
    }

    public String getSampleField() {
        return sampleField;
    }

    public void setSampleField(String sampleField) {
        this.sampleField = sampleField;
    }
}

И в моем файле MainActivity.java япопробуйте создать новый экземпляр:

    try {
        MediaDataMgr.get().addSample(new Sample());
        Timber.d("Lifecycle: was able to add Sample");
    } catch (Exception e) {
        Timber.d("Got exception instantiating Sample: %s", e.getMessage());
    }

Этот метод addSample() использует аналогичный подход к двум классам в этом проекте, которые DO работают:

public String addSample(Sample s) {
    boolean success = true;
    Sample sample;
    Realm realm;
    String retVal = null;
    boolean mainThread = Thread.currentThread().equals(Looper.getMainLooper().getThread());
    if (mainThread) {
        realm = mUIThreadRealm;
    } else {
        realm = Realm.getDefaultInstance();
    }
    try {
        realm.beginTransaction();
        sample = realm.createObject(Sample.class,s.getId()); //<--CRASH!!!!
        sample.setSampleField(s.getSampleField());
    } catch (Exception e ) {
        Timber.d( "Exception adding a Sample: %s", e.getMessage());
        success = false;
    } finally  {

        if ( success ) {
            realm.commitTransaction();
            retVal = s.getId();
        } else {
            realm.cancelTransaction();
        }
        if (!mainThread) {
            realm.close();
        }
    }
    return retVal;
}

Я полностью застрял в этом проекте.

ОБНОВЛЕНИЕ:

Я полностью прокомментировал все ссылки на объект «Контакт» в моем приложении, а затем удалил Contact.java из моего проекта.Я сделал полное перестроение, затем запустил его, и все заработало.

Затем я создал новый класс Contact.java и ввел те же поля и т. Д., Что и раньше, и оставил комментарии без ссылок на него в остальной части моего проекта.,Я сделал перестроение и запустил - и получил ту же ошибку.

Затем я изменил имя класса Contact на ContactSharingInfo , думая, что где-то может быть конфликт имени класса.Перестройте и запустите, и снова - та же ошибка, на этот раз со ссылкой на имя нового класса.

ОРИГИНАЛЬНАЯ ПОЧТА:

Я использую плагин Gradle и процессор аннотаций 5.9.1.Я создал новый класс ("Contact.java"), который изначально работал нормально.Затем я настроил класс (удалил пару полей, добавил новое поле) и начал получать эту ошибку.Я проверил это на Samsung S7 Edge (API 26), а также на нескольких эмуляторах.Та же проблема.

Я сделал все возможное для очистки, перестроения, аннулирования кэширования и перезапуска и т. Д. Не помогло.Я рассмотрел ошибки # 3819 и # 4579 , но ничего там не помогло.Я отключил мгновенный запуск.Не помогает.

Трассировка стека:

realmSet$id:111, com_reddragon_intouch_model_ContactRealmProxy (io.realm)
<init>:30, Contact (com.reddragon.intouch.model)
<init>:26, Contact (com.reddragon.intouch.model)
<init>:84, com_reddragon_intouch_model_ContactRealmProxy (io.realm)
newInstance:96, DefaultRealmModuleMediator (io.realm)
createObjectInternal:1048, Realm (io.realm)
createObject:1024, Realm (io.realm)
addContact:877, MediaDataMgr (com.reddragon.intouch.model)

Код, вызывающий это (addContact () в классе MediaDataMgr, где я централизовал доступ к Realm):

    public String addContact(Contact c, int status) {
        boolean success = true;
        Contact contact;
        Realm realm;
        String retVal = null;
        boolean mainThread = Thread.currentThread().equals(Looper.getMainLooper().getThread());
        if (mainThread) {
            realm = mUIThreadRealm;
        } else {
            realm = Realm.getDefaultInstance();
        }
        try {
            realm.beginTransaction();
            contact = realm.createObject(Contact.class,c.getId()); // <--CRASH HAPPENS HERE
            contact.setEmailAddress(c.getEmailAddress());
            contact.setDisplayName(c.getDisplayName());
            contact.setStatus(status);

        } catch (Exception e ) {
            Timber.d( "Exception adding a contact: %s", e.getMessage());
            success = false;
        } finally  {

                if ( success ) {
                    realm.commitTransaction();
                    retVal = c.getId();
            } else {
                realm.cancelTransaction();
            }
            if (!mainThread) {
                realm.close();
            }
        }
        return retVal;
    }

И класс Contact, на который ссылается трассировка стека:

public class Contact extends RealmObject implements CardListable {
    @PrimaryKey
    private String id;
    private String displayName;
    private String emailAddress;
    private String pathToProfilePic; // This will always be a URI, but we have to store it as a string and convert to URI at runtime.
    @Ignore
    private int status = STATUS_UNKNOWN;

    public Contact() {
        this(UUID.randomUUID().toString());
    }

    private Contact(String id) {
        this.id = id;
    }

    public String getId(){
        return id;
    }

    public String getDisplayName() {
        return displayName;
    }

    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

    public String getEmailAddress() {
        return emailAddress;
    }

    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getPathToProfilePic() {
        return pathToProfilePic;
    }

    public void setPathToProfilePic(String pathToProfilePic) {
        this.pathToProfilePic = pathToProfilePic;
    }

    public String getFirstLineDesc() {
        return displayName;
    }

    public String getSecondLineDesc() {
        return emailAddress;
    }
}

При отладке в классе com_reddragon_intouch_model_ContactRealmProxy.java я обнаружил, что исключение возникает, потому что переменная 'proxyState' равна нулю, когдаметод public String realmSet$id() называется:

    public void realmSet$id(String value) {
        if (proxyState.isUnderConstruction()) { //<-- CRASH HAPPENS HERE
            // default value of the primary key is always ignored.
            return;
        }

        proxyState.getRealm$realm().checkIfValid();
        throw new io.realm.exceptions.RealmException("Primary key field 'id' cannot be changed after object was created.");
    }

, что заставляет меня поверить, что инициализация proxyState в realm$injectObjectContext() не вызывается.

Этот же подход к созданию нового объектаотлично работает с двумя другими классами в этом же проекте, и я проверил, что realm$injectObjectContext() IS вызывается там.Вот трассировка стека в том же типе конструкции для моего класса Media.java (который работает):

realm$injectObjectContext:105, com_reddragon_intouch_model_MediaRealmProxy (io.realm)
<init>:52, Media (com.reddragon.intouch.model)
<init>:49, Media (com.reddragon.intouch.model)
<init>:99, com_reddragon_intouch_model_MediaRealmProxy (io.realm)
newInstance:99, DefaultRealmModuleMediator (io.realm)
createObjectInternal:1048, Realm (io.realm)
createObject:1024, Realm (io.realm)
addMedia:267, MediaDataMgr (com.reddragon.intouch.model)

Так что что-то о том, как генерируется код для класса Contact, должно отличаться от другихэта работа - и это "что-то" сбивает с толку Realm, чтобы не вызывать этот метод.

Что с этим делать?

1 Ответ

0 голосов
/ 07 марта 2019

РЕШЕНИЕ:

В моем случае я был невольной жертвой рефакторинга Lint.Оказывается, я запускал несколько процессов Lint в своих классах, и одним из предложенных изменений было изменение определенных конструкторов, чтобы они были объявлены закрытыми.Очевидно, Realm не нравится это в модельных классах, которые принимают аргументы по умолчанию в конструкторе.Так, например, класс Contact.java имел этот конструктор:

public class Contact extends RealmObject implements CardListable {
    @PrimaryKey
    private String id;
    private String displayName;
    private String emailAddress;
    private String pathToProfilePic; // This will always be a URI, but we have to store it as a string and convert to URI at runtime.
    @Ignore
    private int status = STATUS_UNKNOWN;

    public Contact() {
        this(UUID.randomUUID().toString());
    }

    private Contact(String id) { //<--NOTE PRIVATE CONSTRUCTOR
        this.id = id;
    }

. Изменение на:

public Contact() {
    this(UUID.randomUUID().toString());
}

public Contact(String id) { //<--NOTE THIS IS NOW PUBLIC
    this.id = id;
}

и выполнение clean + rebuild решило проблему.

...