realm / realm-java

Realm is a mobile database: a replacement for SQLite & ORMs
http://realm.io
Apache License 2.0
11.45k stars 1.75k forks source link

I'm pulling empty data, but I've added new data. #7783

Closed adaonder closed 1 year ago

adaonder commented 1 year ago

How frequently does the bug occur?

Sometimes

Description

I'm pulling empty data, but I've added new data. It works fine on most devices but data returns blank on some devices. I've caught firebase null returning devices. For example Redmi Note 8 Pro, Xiaomi M2007J20CG, and some Samsung devices SM-A336E, SM-J415F...

Stacktrace & log output

no error.

Can you reproduce the bug?

Sometimes

Reproduction Steps

My Realm Class;

public class LocalRealmDB { public static final String TAG = LocalRealmDB.class.getName();

public static LocalRealmDB getInstance() {
    return new LocalRealmDB();
}
//public final int SCHEMA_V_PREV = 0;// previous schema version
public final int SCHEMA_V_NOW = 0;// change schema version if any change happened in schema
private RealmConfiguration configuration;
private Realm realm;
private void initRealConfig() {
    try {
        Realm.init(Application.getInstance());
        if (configuration == null) {
            configuration = new RealmConfiguration.Builder()
                    .schemaVersion(SCHEMA_V_NOW)
                    .name(Parameters.Config.LOCAL_DATABASE_REALM_NAME)
                    .allowWritesOnUiThread(true)
                    .allowQueriesOnUiThread(true)
                    .build();//.migration(new CustomRealmMigrations())//.deleteRealmIfMigrationNeeded()
            Realm.setDefaultConfiguration(configuration);
        }
    } catch (Exception ex) {
        Logger.error(TAG, ex.getMessage());
    }
}
private Realm getRealm() {
    initRealConfig();
    if (realm == null) {
        realm = Realm.getDefaultInstance();
    }
    return realm;
}
private void close() {
    //Yeni bir şemeya geçilecekse kapatılır.
    getRealm().close();
    realm = null;
}
public <T extends RealmObject> void saveData(T dataModel, OnResultListenerAdapter<Boolean> listener) {
    getRealm().executeTransactionAsync(realm -> {
        LogUtil.e("saveData insertOrUpdate dataModel");
        realm.insertOrUpdate(dataModel);
    }, () -> {
        LogUtil.e("saveData onSuccess");
        listener.onSuccess("");
    }, error -> {
        LogUtil.e("saveData error: " + error.getMessage());
        listener.onFail("error: " + error.getMessage());
    });
}
public <T extends RealmObject> void saveDataList(List<T> dataList, OnResultListenerAdapter<String> listener) {
    getRealm().executeTransactionAsync(realm -> {
        //Log.e("RED_LOG", "realm");
        realm.insertOrUpdate(dataList);
    }, () -> {
        LogUtil.e("onSuccess");
        listener.onSuccess("");
        //Log.e("RED_LOG", "success");
    }, error -> {
        //Log.e("RED_LOG", "onError");
        LogUtil.e("error: " + error.getMessage());
        listener.onFail("Save Data List: " + error.getMessage());
    });
}
public <E extends RealmObject> List<E> getDataList(Class<E> clazz) {
    LogUtil.e("getDataList");
    RealmResults<E> models = getRealm().where(clazz).findAll();
    return models;
}
public <E extends RealmObject> int getSize(Class<E> clazz) {
    LogUtil.e("getSize");
    return getRealm().where(clazz).findAll().size();
}
public boolean isEmptyData() {
    LogUtil.e("isEmptyData");
    return getRealm().isEmpty();
}
public <E extends RealmObject> E getData(Class<E> clazz) {
    LogUtil.e("getData");
    return getRealm().where(clazz).findAll().last();
}
public <E extends RealmObject> List<E> getDataListWithFieldName(Class<E> clazz, String id, String fieldName) {
    RealmResults<E> models = getRealm().where(clazz).equalTo(fieldName, id).findAll();
    return models;
}
public <E extends RealmObject> boolean isData(Class<E> clazz) {
    RealmResults<E> models = getRealm().where(clazz).findAll();
    return ControlUtil.isData(models);
}
public <E extends RealmObject> boolean isDataWithId(Class<E> clazz, String employeeId) {
    RealmResults<E> models = getRealm().where(clazz).equalTo("employeeId", employeeId).findAll();
    return !models.isEmpty();
}
public <E extends RealmObject> void deleteDataWithId(Class<E> clazz, String id) {
    LogUtil.e("deleteDataWithId");
    getRealm().executeTransactionAsync(transactionRealm -> {
        E model = transactionRealm.where(clazz).equalTo("id", id).findFirst();
        if (model != null) {
            model.deleteFromRealm();
        }
    });
}
public <E extends RealmObject> void deleteAll(Class<E> clazz, OnResultListenerAdapter<String> listener) {
    LogUtil.e("deleteAll");
    getRealm().executeTransactionAsync(realm -> {
        //Delete All
        realm.where(clazz).findAll().deleteAllFromRealm();
    }, () -> {
        listener.onSuccess("");
    }, error -> {
        listener.onFail(error.getMessage());
    });
}

}

Version

10.13.2-transformer-api

What Atlas App Services are you using?

Local Database only

Are you using encryption?

No

Platform OS and version(s)

Android 9,10,11

Build environment

Android Studio version: Android Studio Electric Eel | 2022.1.1 Patch 2 Android Build Tools version: 33 Gradle version: 7.4.2

adaonder commented 1 year ago

get Data code;

List localTerminals = LocalRealmDB.getInstance().getDataList(TerminalRDB.class);

I delete all data before adding data. Code;

LocalRealmDB.getInstance().deleteAll(TerminalRDB.class, new OnResultListenerAdapter() {

        @Override
        public void onSuccess(String message) {
            super.onSuccess(message);

            if (StringUtil.isEmpty(SharedPrefsUtils.getString(Parameters.SharedPref.LAST_CLOCK_RECORD_EVENT_TYPE))) {
                JsonElement lastClockRecordJE = dataJO.get(Parameters.REST.GraphQL.lastClockRecord);

                if (!lastClockRecordJE.isJsonNull()) {
                    ClockRecord clockRecord = DataUtil.getModelDateData(lastClockRecordJE, ClockRecord.class);
                    if (clockRecord != null) {
                        SharedPrefsUtils.setString(Parameters.SharedPref.LAST_CLOCK_RECORD_EVENT_TYPE, clockRecord.getEventType().name());
                    }
                }
            }

            JsonElement filterWithPaginateTerminalsJE = dataJO.get(Parameters.REST.GraphQL.filterWithPaginateTerminals).getAsJsonObject().getAsJsonArray(Parameters.REST.GraphQL.CONTENT);
            if (!filterWithPaginateTerminalsJE.isJsonNull()) {
                List<Terminal> terminalList = DataUtil.getModelDateListData(filterWithPaginateTerminalsJE.getAsJsonArray(), Terminal.class);

                List<TerminalRDB> localTerminals = new ArrayList<>();
                if (ControlUtil.isData(terminalList)) {
                    for (Terminal terminal : terminalList) {
                        TerminalRDB localTerminal = new TerminalRDB();
                        localTerminal.setId(terminal.getId());
                        localTerminal.setName(terminal.getName());
                        localTerminal.setTerminalType(terminal.getTerminalType());
                        localTerminal.setSerialNumber(terminal.getSerialNumber());
                        localTerminal.setQuickPass(terminal.isQuickPass());
                        localTerminal.setClockInOutAllowed(terminal.isClockInOutAllowed());
                        localTerminal.setClockInOutDescriptionRequired(terminal.isClockInOutDescriptionRequired());
                        localTerminal.setDutyInOutAllowed(terminal.isDutyInOutAllowed());
                        localTerminal.setDutyInOutDescriptionRequired(terminal.isDutyInOutDescriptionRequired());
                        localTerminal.setBreakInOutAllowed(terminal.isBreakInOutAllowed());
                        localTerminal.setBreakInOutDescriptionRequired(terminal.isBreakInOutDescriptionRequired());
                        localTerminal.setLunchInOutAllowed(terminal.isLunchInOutAllowed());
                        localTerminal.setLunchInOutDescriptionRequired(terminal.isLunchInOutDescriptionRequired());
                        localTerminal.setImageRequired(terminal.isImageRequired());
                        localTerminal.setInOutManualTakePhotoEnable(BooleanUtils.isTrue(terminal.getInOutManualTakePhotoEnable()) ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
                        localTerminal.setDisabled(terminal.isDisabled());
                        localTerminal.setIndoorTrackingController(terminal.isIndoorTrackingController());
                        localTerminal.setAccessControlEnabled(terminal.isAccessControlEnabled());
                        localTerminal.setEmployeeAccessEnable(terminal.isEmployeeAccessEnable());
                        localTerminal.setCameraRotation(terminal.getCameraRotation());
                        localTerminals.add(localTerminal);
                    }
                }

                //LocalDB.getInstance().addTerminals(localTerminals);
                LogUtil.e("saveDataList ......");
                LocalRealmDB.getInstance().saveDataList(localTerminals, new OnResultListenerAdapter<String>() {

                    @Override
                    public void onSuccess(String message) {
                        super.onSuccess(message);
                        if (listener != null) {
                            listener.onSuccess(message);
                        }
                    }

                    @Override
                    public void onFail(String error) {
                        super.onFail(error);
                        if (listener != null) {
                            listener.onFail(error);
                        }
                        FirebaseUtil.sendLog(error, employeeJWT);
                    }
                });
            }
        }

        @Override
        public void onFail(String error) {
            super.onFail(error);
            if (listener != null) {
                listener.onFail(error);
            }
        }
    });
cmelchior commented 1 year ago

Hi @adaonder

It is a bit hard to follow the flow in your code, but my guess is that you have a timing issue somewhere, i.e. that you are using executeTransactionAsync somewhere and then immediately check for the result instead of waiting for the callback.

If you can provide a minimal project that reproduces the behaviour, we would be able to help you more easily.

adaonder commented 1 year ago

@cmelchior I'm waiting for the onSuccess method then I pull the data. for executeTransactionAsync.

getRealm().executeTransactionAsync(realm -> { //Log.e("RED_LOG", "realm"); realm.insertOrUpdate(dataList); }, new Realm.Transaction.OnSuccess() -> { LogUtil.e("onSuccess"); RealmResults models = getRealm().where(clazz).findAll();

        models.size() // 0
    }, error -> {
        //Log.e("RED_LOG", "onError");
        LogUtil.e("error: " + error.getMessage());
    });
adaonder commented 1 year ago

thanks. no problem.