Search code examples
androidjvmandroid-roomfts4

Setting unique indices in @FTS4 Room database causes build error


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?


Solution

  • 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.