2

I have an Android app, that uses an SQLite database to store 2-dimensional data in an R-Tree with the SQLite R*-Tree Module.

As updated in June 2017, the pre-built version of SQLite now has this module enabled by default, so I don't have to build it myself anymore. I'm using that SQLite library instead of the android.database.sqlite library.

My question is now, can I use the Android Room library to access my database, give that it internally uses another SQLite library?

When I try to query an existing database that has been filled by another process, I get the following exception:

android.database.sqlite.SQLiteException: no such module: rtree (code 1): , while compiling: SELECT * FROM r_tree WHERE minX <= ? AND maxX >= ? AND minY <= ? AND maxY >= ?
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:500)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1318)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1293)
at androidx.sqlite.db.framework.FrameworkSQLiteDatabase.query(FrameworkSQLiteDatabase.java:161)
at androidx.room.RoomDatabase.query(RoomDatabase.java:305)
at androidx.room.util.DBUtil.query(DBUtil.java:54)
at at.mycompany.app.android.myfeature.persistance.RTreeDao_Impl.getObjectsInBoundingBox(RTreeDao_Impl.java:36)
at at.mycompany.app.android.myfeature.ReadmyfeatureDatabaseTest.readRTreeObjects(ReadmyfeatureDatabaseTest.java:133)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:80)
at androidx.test.internal.runner.junit4.statement.RunAfters.evaluate(RunAfters.java:61)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:104)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:392)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2074)

So it seems that Room uses another SQLite library internally, not the one I have included in my app. Is there a possibility to swap this? Or any other way to enable Room to be able to read from an R-Tree table, or do I have to write a raw query for that request?

Alexander Pacha
  • 9,187
  • 3
  • 68
  • 108
  • Did you ever manage to do it? – Ernest Zamelczyk Nov 17 '20 at 13:05
  • Yes, by following the answer from below and doing some copy-paste-edit stuff of existing wrapper classes. – Alexander Pacha Nov 17 '20 at 13:53
  • I did exactly that but the SQLiteOpenHelper from the aar package doesn't resolve the path to the database from context when it's writeable and my app crashes every time. – Ernest Zamelczyk Nov 18 '20 at 10:20
  • You will have to replace all these helper classes that import/load the SQL database module. Basically, go ahead, grab the existing implementation and replace the import statements in all of them and then use your own SQLiteOpenHelper implementation. You're done, once there is no more `import android.database.sqlite` in your code but only `import org.sqlite.database.sqlite` – Alexander Pacha Nov 19 '20 at 10:52

1 Answers1

2

So it seems that Room uses another SQLite library internally, not the one I have included in my app

Step #8 of your linked-to instructions is "Replace SQlite imports to org.sqlite.database.sqlite.xxxxxx". Room isn't somehow going to automagically do that.

Is there a possibility to swap this?

You would need to write an implementation of the SupportSQLite* set of interfaces that connects to your SQLite library. One of those will be a SupportSQLiteHelper.Factory, and you will need to supply an instance of that to your RoomDatabase.Builder via openHelperFactory().

You can see implementations of this in:

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491