Android Question Can not copy/open database?

Guenter Becker

Active Member
Licensed User
Hello, hope you are fine.
At present I have a probleme that I did not have before updating b4a suite to 11.20. and I need professional help.

starter/sub service_create:
Sub Process_Globals
    Public SQLite As SQL                    ' Database object Sqlite Version 3
End Sub

Sub Service_Create
    Try
        ' # copy Database to accessable directory and open database
        DBUtils.CopyDBFromAssets("FDM.db")
        if file.exists(DBUtils.GetDBFolder,"FDM.db") then
            SQLite.Initialize(DBUtils.GetDBFolder,"FDM.db",false)
        end if
    Catch
        xui.Msgbox2Async("Datenbank nicht geöffnet!" & CRLF & CRLF & LastException, _
            "10: Datenbankfehler","OK","","",Main.imgError)
    End Try
End Sub
I run the app on my real device and on emulator and checked with a filemanger that the database file is copied and resists in the directory - it does!
I am not able to initialize/open the database. By the way I did not change the Database Version.

Next I tried t copy the database file manually with file.copy and by using xui,DefaultFolder same problem.

I got this error message as followes:

Logger verbunden mit: HUAWEI CLT-L29
--------- beginning of crash
--------- beginning of system
--------- beginning of main
Copying updated assets files (24)
*** Service (starter) Create ***
Error occurred on line: 56 (Starter)
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (Sqlite code 14): Could not open database, (OS error - 2:No such file or directory)
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:225)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:541)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:209)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:198)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:936)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:923)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:821)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:770)
at anywheresoftware.b4a.sql.SQL.Initialize(SQL.java:44)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:777)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:354)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:193)
at FDM.Prof.starter.onCreate(starter.java:56)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3795)
at android.app.ActivityThread.-wrap5(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1984)
at android.os.Handler.dispatchMessage(Handler.java:109)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7367)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:469)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:963)

Thank you for assistance and responding.
 

DonManfred

Expert
Licensed User
Longtime User
HOW should one help here? You are not providing enough informations.
for ex: What is the value of DBUtils.GetDBFolder?
 
Upvote 0

toby

Well-Known Member
Licensed User
Longtime User
Try on different devices than HUAWEI which isn't a standard Android device.
 
Upvote 0

Guenter Becker

Active Member
Licensed User
Ok Ok ....
Target Device Android 8.1.0
Target App SDK Min 25 target checked 28/29/30
SDK paket checkt is installed
GetDBFolder: /storage/emulated/0/Android/data/FDM.Prof/files
if file.exists(DBUtils.GetDBFolder,"FDM.db") then .... reports True
B4XBridge System Rights: Storage
 
Upvote 0

Guenter Becker

Active Member
Licensed User
Does also this check:
B4X:
DBUtils.CopyDBFromAssets("fdm.db")
    Dim l As List
    l = File.ListFiles(DBUtils.GetDBFolder)
    Log (l)
    SQlite.Initialize(DBUtils.GetDBFolder,"fdm.db",False)

Log Result: (ArrayList) [fdm.db] ... so the file is there
I checked also the database its ok and can be opended by SqLite Expert

And no did not change my phone.
Checked it on emulator and NOX as well same problems.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
B4XBridge System Rights: Storage
This has nothing to do with it. B4XBridge needs storage permissions to save the apk for installation. It's nothing to do with your app.

Target App SDK Min 25
Min SDK is not what we want,what is the targetSdkVersion? If it is 23 or higher (I think) you need to get permission for WRITE_EXTERNAL_STORAGE using runtime permissions. As you are doing this in Service_Create I can see no permissions request.

If the targetSdkVersion is 29 or greater you have a problem accessing arbitrary file locations

For targetSdkVersion 30 and above you are limited to these options
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
GetDBFolder: /storage/emulated/0/Android/data/FDM.Prof/files
So this is your Apps internal Files folder (which is readonly!).
You can not use a Database from your Files folder. The Database must be copied to an accessable path first.

B4X:
DBUtils.CopyDBFromAssets("FDM.db")
probably is doing just this. If so you should use the new path to open the databasefile.
 
Last edited:
Upvote 0

agraham

Expert
Licensed User
Longtime User
You can not use a Database from your Files folder.
I don't think that is correct. File.DirAssets is read only. Intellisense says File.DirInternal is "used to save application private data"
Actually it looks like File.DirDefaultExternal which is also writeable.
 
Upvote 0

Guenter Becker

Active Member
Licensed User
Now I go back to the roots:
Create clean Project "b4a.example"
Add to manifest file:
AddManifestText(
<uses-permission
  android:name="android.permission.WRITE_EXTERNAL_STORAGE"
/>
)
code in main page/activity:
    Dim pm As B4XPagesManager
    pm.Initialize(Activity)
    Dim rp As RuntimePermissions
    If rp.Check(rp.PERMISSION_WRITE_EXTERNAL_STORAGE) = False Then _
        rp.CheckAndRequest(rp.PERMISSION_WRITE_EXTERNAL_STORAGE)
       
    File.Copy(File.DirAssets,"fdm.db",xui.DefaultFolder,"fdm.db")
    Log(xui.DefaultFolder)
   
    Dim l As List
    l = File.ListFiles(xui.DefaultFolder)
    Log (l)
   
    sqlite.Initialize(xui.DefaultFolder,"fdm.db",False)

Log output:
/data/user/0/b4a.example/files
(ArrayList) [WeatherForecast.txt, virtual_assets, acr1255u.pdf, fdm.db]

As we see in the Log output fdm.db is copied
And sql.initialize: the same Error message as in my first post.

I knock my head what in the hell is going wrong here?
  • Permissions are set.
  • File is copied (364kb).
  • Database is checked and Ok.
  • Same Device with same OS as before.
  • All SDKs installed
  • Using sqlite.Initialize(xui.DefaultFolder,"fdm.db",true is workign! But doing so
    I have an empty Database.
I never had such problems and I can't find whats going wrong.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
Yes. I agree with auric. For the code above permissions should not be needed.

It's a long shot but remove the permissions code (you don't need to add the manifest entry anyway) and try a Sleep(500) between the copy and trying to open the database. I seem to remember having a similar problem some time ago where Android seemed to need a return to the message loop to complete a file operation that should have been synchronous but appeared not in practice. If this doesn't work I'm afraid I'm out of ideas.
 
Upvote 0

vecino

Well-Known Member
Licensed User
Longtime User
Just to try it out, try this:

B4X:
File.Copy(File.DirAssets,"fdm.db",File.DirInternal,"fdm.db")
sqlLite.Initialize(File.DirInternal,"fdm.db",False)

I also see in the attached codes that you have put fdm.db and FDM.db and as you know, it is case sensitive.
He hopes it will do some good.
 
Upvote 0

Guenter Becker

Active Member
Licensed User
Hi, I found the solution! Do'nt ask me why.


Solution:
        ' # copy Database to accessable directory and open database
        File.Copy(File.DirAssets,"fdm.db",File.DirInternal,"fdm.db")
        If File.Exists(File.DirDefaultExternal,"fDM.db") Then
            Sleep(500)
            SQLite.Initialize(File.DirDefaultExternal,"fDM.db",False)
        End If

-> using DirDefaultExternal and it works.
 
Upvote 0

vecino

Well-Known Member
Licensed User
Longtime User
Then it is because it is using File.DirInternal.

B4X:
'Returns the path to a folder where you can create a database, preferably on the secondary storage.
Public Sub GetDBFolder As String
    Dim rp As RuntimePermissions
    If File.ExternalWritable Then Return rp.GetSafeDirDefaultExternal("") Else Return File.DirInternal
End Sub

Note that your code is wrong.

First you copy fdm.db in lowercase to file.dirInternal and then you search fDM.db in uppercase in file.DirDefaultExternal.
 
Upvote 0
Top