Android Question KeyValueStore read error from new file first time only - SOLVED

mln

Member
Licensed User
Longtime User
I am having an issue reading from a KeyValueStore directly after copying the associated filed from assets to the internal directory. Any read or write after that initial copy works as it should even when the program is re-run or a new version of the program is generated.
When the program is run for the first time, it checks to make sure the file is in the internal directory. If it is not, it copies it from assets to the internal directory. In the error below, I logged the keys stored in the file, so I know the file was copied and is open and it contains the keys at least.
My data are user types as follows:

B4X:
Type msa(F As Double, zo As Double, ang As Double, w As Double, l As Double, eff As Double, loss As Double, td As Double)
Type msb(er As Double, h As Double, t As Double, tanS As Double, rho As Double, rough As Double)
Type Units(w As Int, l As Int, h As Int, t As Int, F As Int)

Here is the error:

** Activity (main) Create, isFirst = true **
(ArrayList) [msm, msmb, msu]

keyvaluestore_getobjectinternal (B4A line: 163)
res = raf.ReadObject(raf.CurrentPosition)
java.lang.IllegalArgumentException: invalid value for field
at java.lang.reflect.Field.setField(Native Method)
at java.lang.reflect.Field.set(Field.java:558)
at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.readType(RandomAccessFile.java:500)
at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.readObject(RandomAccessFile.java:476)
at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.readHelper(RandomAccessFile.java:401)
at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.ReadObject(RandomAccessFile.java:362)
at com.mmctec.pfm.keyvaluestore._getobjectinternal(keyvaluestore.java:360)
at com.mmctec.pfm.keyvaluestore._getobject(keyvaluestore.java:304)
at com.mmctec.pfm.main._activity_create(main.java:301)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
at com.mmctec.pfm.main.afterFirstLayout(main.java:89)
at com.mmctec.pfm.main.access$100(main.java:16)
at com.mmctec.pfm.main$WaitForLayout.run(main.java:74)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3806)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
java.lang.IllegalArgumentException: invalid value for field
** Activity (main) Resume **


If I continue running, all values from the file are set to zero so I assume no values were actually read. But from here on out, I can update and read data from the file correctly even when the program terminates and re-runs. This error only shows up on a fresh install the first time it is run.

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim m As msa
    Dim mb As msb
    Dim u As Units
    Dim kvs As KeyValueStore
   
End Sub

B4X:
 Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("msl")
    I.Initialize("IME")
    I.AddHeightChangedEvent
    scrView.Initialize(100%y)
    Activity.AddView(scrView, 0, 0, 100%x, 100%y)
    scrView.Panel.LoadLayout("msl")
      
    If FirstTime = True Then      
        CopyFromAssets("mmcMWL.conf")  
        kvs.Initialize(File.DirInternal, "mmcMWL.conf")
    End If
  
    Log(kvs.ListKeys)
    m = kvs.GetObject("msm")
    mb = kvs.GetObject("msmb")
    u = kvs.GetObject("msu")
    SetEntries
    SetSpinners
  
'    File.Copy(File.DirInternal, "mmcMWL.conf", File.DirRootExternal, "mmcMWL.conf")
  
End Sub

B4X:
Sub CopyFromAssets(str As String)
    Dim tgt, tsrc As String
 
    tgt = File.DirInternal
    tsrc = File.DirAssets
 
    If File.exists(tgt, str) = False Then
        File.Copy(tsrc, str, tgt, str)
    End If
 
End Sub

Any help on this would be greatly appreciated, I assume I am doing something boneheaded

Versions: B4A 2.70, SQL 1.20, RAF 1.32, KVS 1.00
 

thedesolatesoul

Expert
Licensed User
Longtime User
Move kvs references inside FirstTime since that is only when you initialize it.
B4X:
If FirstTime = True Then     
        CopyFromAssets("mmcMWL.conf") 
        kvs.Initialize(File.DirInternal, "mmcMWL.conf")
        Log(kvs.ListKeys)
      m = kvs.GetObject("msm")
      mb = kvs.GetObject("msmb")
      u = kvs.GetObject("msu")
    End If
 
  • Like
Reactions: mln
Upvote 0

mln

Member
Licensed User
Longtime User
Good point. I will be making that change.

As for the problem, I am now wondering if I am trying to read from the file to quickly after copying it. Anyone know of file write times in android? When I get home, I think I will recode to grab the values from the asset file if the internal file does not exist and create the internal directory file at the same time. Then during activity_pause I will write the data to the new file.
 
Upvote 0

mln

Member
Licensed User
Longtime User
Problem solved. I tried pulling the values directly from the assets directory and when I kept getting "unable to open database file" errors, I decided to look in the generated apk file to see if the file was actually there. It was of course, BUT in all lower case (doh!). Odd thing is, in my main project directory, I have the file with uppercase letters in it. Not sure why, but it looks like B4A stuffs it in the apk all lower case when the program is compiled. Lesson learned, when having troubles with files check the case!
 
Upvote 0
Top