Android Question SQLiteReadOnlyDatabaseException

RVP

Active Member
Licensed User
Longtime User
I have suddenly started to get this error after I uninstalled and reinstalled my app

Here is the relevant code and the error log. Note that I am accessing this database in other modules and have no issues with writing to any of the other tables in it.

B4X:
In my Main Activity

Sub Activity_Create(FirstTime As Boolean)
    If FirstTime Then

       If File.Exists(File.DirDefaultExternal,DbFileName) = False Then
           DBUtils.CopyDBFromAssets(DbFileName)
           DBUtils.CopyDBFromAssets(DbFileName2)
       End If
    StartService(Location)
    End If
End Sub

In the Location Service

Dim DbFileName As String : DbFileName = "WorkOrder.db"
       
       
        SQL1.Initialize(File.DirDefaultExternal,DbFileName,False)
       .
       .
       . code setting up maps
       .
        DBUtils.InsertMaps(SQL1,"WOLO",lMaps)
       
        Log Entry
       
        InsertMaps (first query out of 1): INSERT INTO [WOLO] ([employee_id], [l_stamp], [latitude], [longitude], [bearing], [accuracy], [speed], [app_status]) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        (SQLiteReadOnlyDatabaseException) android.database.sqlite.SQLiteReadOnlyDatabaseException: attempt to write a readonly database (code 1032)


I haven't changed anything relating to this code for a while, the only thing that has changed is that I completely uninstalled and reinstalled the app, instead of just updating it.
 

RVP

Active Member
Licensed User
Longtime User
if it wasn't being copied to the dirdefaultexternal, wouldn't there be an error on trying to open it from there?


In any case, why would writing to this one table in the database from the service give an error, when writing to the same database but a different table in other activitys does not.

And after the first time the app is run, the database already exists so the copy isn't occurring anyways but this error is still occurring.

Is there an problem if you open the same database more than once from different activities/services?
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
DBUtils.CopyDBFromAssets returns the folder that the database was copied to. It can be different than File.DirDefaultExternal.
This means that if you use CopyDBFromAssets the db file could be copied to DirInternal; so, after you should not use DirDefaultExternal but you should use a variable like DBDir which will contain the string returned by CopyDBFromAssets.
Also, CopyDBFromAssets checks if the db file already exists, you will not need to verify this.

If you move all, declarations and initializations, to the Starter service, declaring SQL1 as Public, then you will have no more problems, simply run you db commands (I think it should be better to create a code module with all your db commands), using Starter.SQL1.....


P.S. Also, you are copying TWO db files
 
Last edited:
Upvote 0

RVP

Active Member
Licensed User
Longtime User
I am sorry, this doesn't make sense. This app has been running for years. The database is copied once, when the app is first run after installing. The format I am using is exactly as Erol demonstrated on the dbutils. I can access other tables in the same database by opening SQL on dirdefaultexternal so the database is obviously in that location. If the database wasn't on dirdefaultexternal I should get an error when opening it.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
I am sorry, this doesn't make sense. This app has been running for years.
I can access other tables in the same database

Also this has no sense:
In the Location Service

Dim DbFileName As String : DbFileName = "WorkOrder.db"

In my Main Activity

Sub Activity_Create(FirstTime As Boolean)
If FirstTime Then

If File.Exists(File.DirDefaultExternal,DbFileName) = False Then
How can you declare and set DbFileName in your Location Service but then you copy the db in Activity_Create of Main using a variable which is not declared there?
The code should be:
B4X:
If File.Exists(File.DirDefaultExternal, Location.DbFileName) = False Then
Since it works (?), you should have (at least) two DbFileName declared.

It is just to say that maybe I wrote nonsense but surely your code is a little bit confused.

Try to add many logs (especially to be sure on which db file you are working on and where it is) and run your project in debug mode, step by step.
I don't think we can help you in another way (or at least I can't).
 
Last edited:
Upvote 0

RVP

Active Member
Licensed User
Longtime User
I do declare that variable in the activity as well, I didn't include all of the code from each module, as if I hadn't declared that variable I wouldn't be able to compile, let alone run
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
The format I am using is exactly as Erol demonstrated on the dbutils.
That's not true. You must use the folder returned from CopyDBFromAssets.

I do declare that variable in the activity as well
You should have a single SQL object in the starter service. You can use it from other modules.
 
Upvote 0

RVP

Active Member
Licensed User
Longtime User
Alright I will defer to you, you should know.

When you say you should have a single SQL object, is that a best practice, or a requirement. Does that mean that I cannot open the same database more than once?

I will read up on starter services.
 
Upvote 0

RVP

Active Member
Licensed User
Longtime User
Forgot to ask, if dbutils isn't copying the database to external, shouldn't I be getting and error when I try to open it from there? Also, why would it not be able to copy it to external.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Forgot to ask, if dbutils isn't copying the database to external, shouldn't I be getting and error when I try to open it from there? Also, why would it not be able to copy it to external.
You should decide if use CopyDBFromAssets or not, you're not obligated.

You can decide where to store your db and than use directly File.DirDefaultExternal, for example; but if you use CopyDBFromAssets you should know how it works (see its code). It chooses between DirDefaultExternal, if possible, otherwise DirInternal, RETURNING "where" it has copied.

You can also modify CopyDBFromAssets according to your needs.
 
Upvote 0

RVP

Active Member
Licensed User
Longtime User
Ok, moved all of my SQL initialization into a starter service and everything is working again.
 
Upvote 0
Top