Setting unique indices in @FTS4 Room database causes build error

265 Views Asked by At

I tried to make a column of my Room database unique by defining indices. However, this caused my compiler to fail, as it drastically increases the required object heap.

If I use @Entity(tableName = "seeds", indices = {@Index(value = {"name"}, unique = true)}) @Fts4

I get a compiler error when running "gradlew build --stacktrace":

Error occurred during initialization of VM
Could not reserve enough space for 3145728KB object heap

If I just use @Entity(tableName = "seeds") @Fts4, the app properly compiles.

I tried different settings in my gradle.properties...

org.gradle.jvmargs=-Xmx3g was the largest value I could give it. At 4g it complains that the value exceeds the allowed maximum. So all other SO threads regarding this are not helpfull as I already went to the maximum. I usually have it at 2g. So this "small" change seems to double the required object heap.

Does anyone know a better way to handle unique indices?

Does anyone know how to solve the object heap issue at this level?

1

There are 1 best solutions below

0
Tobi On BEST ANSWER

As @CommonsWare stated, it seems like @FTS4 tables do not support indices.

On the website https://developer.android.com/training/data-storage/room/defining-data they mention:

If your app must support SDK versions that don't allow for using FTS3- or FTS4-table-backed entities, you can still index certain columns in the database to speed up your queries.

What let's me assume now, that they do not support indices on FTS3/4..

I solved uniqueness now with a workaround, that checks whether there is a match in the column before inserting a new object:

/**
 * Add a SeedEntity object to the database,
 * if there is no entity in the database with the same name (non-case-sensitive)
 *
 * @param seedEntity Object that is supposed to be added to the database
 * @return  whether the Object has been added or not
 */
public boolean addSeed(SeedEntity seedEntity)
{
    for (SeedEntity entity : mObservableSeeds.getValue())
        if (entity.getName().toLowerCase().equals(seedEntity.getName().toLowerCase()))
            return false;

    mExecutors.diskIO().execute(() ->
            mDatabase.runInTransaction(() ->
                    mDatabase.seedDao().insert(seedEntity)
            )
    );
    return true;
}

Not exactly what I was looking for, but solves the purpose now.