Skip to content

Instantly share code, notes, and snippets.

@carloseduardosx
Last active January 18, 2021 05:36
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save carloseduardosx/6c3a3dfc3a9cb467aa464884f39544c2 to your computer and use it in GitHub Desktop.
Save carloseduardosx/6c3a3dfc3a9cb467aa464884f39544c2 to your computer and use it in GitHub Desktop.
RealmAutoIncrement is a singleton which maintain the last id saved from each database model
package com.carloseduardo.model;
import com.carloseduardo.constants.KnownClasses;
import com.carloseduardo.exception.UnknownModelException;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
import io.realm.annotations.Required;
/**
* @author Carlos Eduardo
* @since 03/09/2016
*/
public class AutoIncrementEntity extends RealmObject {
@Required
@PrimaryKey
private Integer _id = 1;
private Integer accountType;
private Integer equipment;
private Integer location;
public Integer getId() {
return _id;
}
public Integer getAccountType() {
return accountType;
}
public void setAccountType(Integer accountType) {
this.accountType = accountType;
}
public Integer getEquipment() {
return equipment;
}
public void setEquipment(Integer equipment) {
this.equipment = equipment;
}
public Integer getLocation() {
return location;
}
public void setLocation(Integer location) {
this.location = location;
}
public void incrementByClassName(String className) {
switch (className) {
case KnownClasses.ACCOUNT_TYPE:
accountType = accountType == null ? 1 : ++accountType;
break;
case KnownClasses.EQUIPMENT:
equipment = equipment == null ? 1 : ++equipment;
break;
case KnownClasses.LOCATION:
location = location == null ? 1 : ++location;
break;
default:
throw new UnknownModelException("Class name: " + className);
}
}
public Integer findByClassName(String className) {
switch (className) {
case KnownClasses.ACCOUNT_TYPE:
return this.accountType;
case KnownClasses.EQUIPMENT:
return this.equipment;
case KnownClasses.LOCATION:
return this.location;
default:
throw new UnknownModelException("Class name: " + className);
}
}
}
package com.carloseduardo.application;
import android.app.Application;
import android.content.Context;
import io.realm.Realm;
import io.realm.RealmConfiguration;
/**
* @author Carlos Eduardo
* @since 03/09/2016
*/
public class CustomApplication extends Application {
private static CustomApplication application;
@Override
public void onCreate() {
super.onCreate();
application = this;
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
.build();
Realm.setDefaultConfiguration(realmConfiguration);
}
public static CustomApplication getApplication() {
return application;
}
public static Context getContext() {
return application;
}
}
package com.carloseduardo.constants;
/**
* @author Carlos Eduardo
* @since 03/09/2016
*/
public interface KnownClasses {
String ACCOUNT_TYPE = "AccountType";
String EQUIPMENT = "Equipment";
String LOCATION = "Location";
}
package com.carloseduardo.database;
import android.support.annotation.NonNull;
import android.util.Log;
import com.carloseduardo.application.CustomApplication;
import com.carloseduardo.model.AutoIncrementEntity;
import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmObject;
/**
* Simple implementation of Auto Increment feature for Realm
*
* RealmAutoIncrement is a singleton which maintain the last id saved from each model.
* <p/>
* To get next id from anyone model, simple call the method getNextIdFromModel.
*
* @see #getNextIdFromModel(Class)
*
* @author Carlos Eduardo
* @since 03/09/2016
*/
public final class RealmAutoIncrement {
private static RealmAutoIncrement autoIncrementMap;
private RealmAutoIncrement() {
createAutoIncrementEntityIfNotExist();
}
/**
* Search in AutoIncrementEntity for the last saved id from model passed and return the next one
*
* @param clazz Model which should get the next id
* @return The next id which can be saved in database
*/
public Integer getNextIdFromModel(Class<? extends RealmObject> clazz) {
if (isValidMethodCall()) {
Integer id = updateIdByClassName(clazz);
Log.i("RealmAutoIncrement", "getNextIdFromModel: " + id);
return id;
}
Log.e("RealmAutoIncrement", "getNextIdFromModel is called by a not valid method");
return null;
}
private Integer updateIdByClassName(final Class<? extends RealmObject> clazz) {
Realm realm = getRealm();
final AutoIncrementEntity autoIncrementEntity = realm.where(AutoIncrementEntity.class).findFirst();
if (realm.isInTransaction()) {
autoIncrementEntity.incrementByClassName(clazz.getSimpleName());
realm.copyToRealmOrUpdate(autoIncrementEntity);
} else {
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
autoIncrementEntity.incrementByClassName(clazz.getSimpleName());
realm.copyToRealmOrUpdate(autoIncrementEntity);
}
});
}
return autoIncrementEntity.findByClassName(clazz.getSimpleName());
}
/**
* Utility method to validate if the method is called from reflection,
* in this case is considered a not valid call otherwise is a valid call
*
* @return The boolean which define if the method call is valid or not
*/
private boolean isValidMethodCall() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for (StackTraceElement stackTraceElement : stackTraceElements) {
if (stackTraceElement.getMethodName().equals("newInstance")) {
return false;
}
}
return true;
}
private void createAutoIncrementEntityIfNotExist() {
AutoIncrementEntity autoIncrementEntity = getRealm().where(AutoIncrementEntity.class).findFirst();
if (autoIncrementEntity == null) {
createAutoIncrementEntity();
}
}
private void createAutoIncrementEntity() {
getRealm().executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
AutoIncrementEntity autoIncrementEntity = new AutoIncrementEntity();
realm.copyToRealm(autoIncrementEntity);
}
});
}
private Realm getRealm() {
return Realm.getInstance(getRealmConfiguration());
}
@NonNull
private RealmConfiguration getRealmConfiguration() {
//TODO Change for your current RealmConfiguration
return new RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
.build();
}
public static RealmAutoIncrement getInstance() {
if (autoIncrementMap == null) {
autoIncrementMap = new RealmAutoIncrement();
}
return autoIncrementMap;
}
}
package com.carloseduardo.exception;
/**
* @author Carlos Eduardo
* @since 03/09/2016
*/
public class UnknownModelException extends RuntimeException {
public UnknownModelException() {
}
public UnknownModelException(String message) {
super(message);
}
}
@carloseduardosx
Copy link
Author

carloseduardosx commented Sep 3, 2016

Sample of how to use the RealmAutoIncrement

package com.carloseduardo.model;

import com.carloseduardo.database.RealmAutoIncrement;

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

public class AccountType extends RealmObject {

    @Required
    @PrimaryKey
    private Integer _id = RealmAutoIncrement.getInstance().getNextIdFromModel(AccountType.class);

    public Integer getId() {
        return _id;
    }

    private String key;

    private String description;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

Change the RealmAutoIncrement.getRealmConfiguration() to return your own configuration.

NOTE: ClassName declared in the interface KnownClasses should have the same name of the referenced class.

@eloquentbit
Copy link

Hi, thanks for this gist. I've a problem: when I try to use this class I obtain the error: getNextIdFromModel is called by a not valid method. My object is created with this code:

realm.executeTransactionAsync(new Realm.Transaction() {
  @Override
   public void execute(Realm realm) {
     Task newTask = realm.createObject(Task.class);
     newTask.setTitle(taskTitleInput.getText().toString());
   }
}

The Task class:

public class Task extends RealmObject {

    public static final String TITLE = "title";

    @Required
    @PrimaryKey
    private Integer _id = RealmAutoIncrement.getInstance().getNextIdFromModel(Task.class);

    @Required
    private String title;
    private String description;
    private boolean isCompleted;
    private Date dueDate;

    public Task() {}

    public Task(String title, String description, Date dueDate) {
        this.title = title;
        this.description = description;
        this.isCompleted = false;
        this.dueDate = dueDate;
    }

    public Integer getId() {
        return _id;
    }

Thanks

@eloquentbit
Copy link

It seems that it's not a problem; I obtain that message only when my activity reads the content of the realm db.

@carloseduardosx
Copy link
Author

carloseduardosx commented Oct 13, 2016

Apologize for the delay @eloquentbit. That message is because Realm create a new instance of your model by reflection when he's persisting your data. In this case the AutoIncrementEntity shouldn't increment the model id

@NizarETH
Copy link

NizarETH commented Feb 8, 2017

Hi bro, you should update Realm Configuration, in your file RealmAutoIncrement remplace this line : return new RealmConfiguration.Builder(CustomApplication.getContext()) .deleteRealmIfMigrationNeeded() .build(); by this new line return new RealmConfiguration.Builder() .deleteRealmIfMigrationNeeded() .build(); and do the same thing in your Application's class.

@NizarETH
Copy link

NizarETH commented Feb 8, 2017

Also, you should update @Required @PrimaryKey private Integer _id = RealmAutoIncrement.getInstance().getNextIdFromDomain(AccountType.class); it becomes getNextIdFromModel not getNextIdFromDomain

@carloseduardosx
Copy link
Author

Thanks for the update @IvanovE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment