B4A Class KeyValues - Extended KeyValueStore

Discussion in 'Additional libraries, classes and official updates' started by derez, Sep 10, 2013.

  1. derez

    derez Expert Licensed User

    Working on an application with Erel's KeyValueStore, I had the need to store more than one value per key.
    Of course, it is always possible to combine several values to one (create a type or combine to comma separated string) but then you get all of them, have to break the package and use the value you need.
    The attached class is an extension of the KeyValueStore, enabling storing of many values of different types per one key, storing and retrieving each value alone or as an array of values.
    for almost each method in KVS there are two methods here:
    - for handling a single value - use the method ending with 1
    - for handling an array of values - use the method ending with 2
    The index added to the methods type 1 is the number of the value in the key-values line, starting with 0.
    Also added GetKeyBySimpleValue which is missing in regular maps.
    The demo holds, in addition to new demo methods, a commented part of the original demo of KVS (with addition of index).

    Edit: ver 1.1 , improved GetKeyBySimpleValue.

    Edit:
    Sometimes you'll want to store values that are related to two keys, like for example the statistics of a basketball player - you'll have name and statistics type as the keys.
    Or, several velues per two keys - if you want to store several teams data- you'll have team and player as keys, array of values for all types of statistics.
    So I added two more store classes- both with two keys, one with single value, the other with single or array of values.
    The structure of these classes is the same as the previously published so there is no demo.
     

    Attached Files:

    Last edited: Sep 21, 2013
  2. derez

    derez Expert Licensed User

    Ver 1.1 , improved GetKeyBySimpleValue.
     
  3. derez

    derez Expert Licensed User

    Sometimes you'll want to store values that are related to two keys, see the first post for additional classes.
     
  4. schimanski

    schimanski Well-Known Member Licensed User

    First, thanks for this amazing lib.....

    I only have one problem:

    in line

    Code:
    If c.RowCount = 0 Then Return ""
    of the sub 'Public Sub GetSimple1(Key As String, index As Int) As String' in the keyvalue-class, i get the following exception, when I start my app after a few minutes again:

    Code:
    android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=601 (# cursors opened by this proc=601)
       at android.database.CursorWindow.<init>(CursorWindow.java:
    108)
       at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:
    198)
       at android.database.sqlite.SQLiteCursor.clearOrCreateWindow(SQLiteCursor.java:
    301)
       at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:
    139)
       at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:
    133)
       at anywheresoftware.b4a.sql.SQL$CursorWrapper.getRowCount(
    SQL.java:313)
       at de.sekutor.eis.keyvalues._getsimple1(keyvalues.java:
    839)
       at de.sekutor.eis.ladeservice._uploadtimer_tick(ladeservice.java:
    2757)
       at java.lang.reflect.Method.invoke(Native Method)
       at java.lang.reflect.Method.invoke(Method.java:
    372)
       at anywheresoftware.b4a.BA.raiseEvent2(BA.java:
    187)
       at anywheresoftware.b4a.objects.Timer$TickTack.run(
    Timer.java:105)
       at android.os.Handler.handleCallback(Handler.java:
    739)
       at android.os.Handler.dispatchMessage(Handler.java:
    95)
       at android.os.Looper.loop(Looper.java:
    145)
       at android.app.ActivityThread.main(ActivityThread.java:
    5834)
       at java.lang.reflect.Method.invoke(Native Method)
       at java.lang.reflect.Method.invoke(Method.java:
    372)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:
    1388)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:
    1183)
    I always check, if the keyvalue is initialized, before I initialize it.
     
  5. derez

    derez Expert Licensed User

    I don't know, I read
    Maybe it is a problem of memory, what size of object is expected as a returned value ? Try to close the aplication before re-activating (using the menu).
    If it is not solved - please show the calling sub.
     
  6. schimanski

    schimanski Well-Known Member Licensed User

    Thanks, derez for your response. I have tested more and I think, the problem is my code. I have a service-modul with a timer. The exception is always raised, after the timer is raised 19 times, even the timer is 2000 oder 20000 ms.


    Code:
    'Service-Modul'
    Sub Process_Globals
         
    Private UploadTimer As Timer 
         
    Public Gesendet As KeyValues 
         ...
    end sub
    Sub UploadTimer_Tick   
            
    If Gesendet.IsInitialized=False Then Gesendet.Initialize(File.DirInternal, "Gesendet.eis"2)
           
            
    If Gesendet.ListKeys.Size>0 Then
                
    For i=0 To Gesendet.ListKeys.Size-1
                    
    If Gesendet.GetSimple1(Gesendet.ListKeys.Get(i),0)<>Null AND Gesendet.GetSimple1(Gesendet.ListKeys.Get(i),0)="False" Then
                           ......
                           ......
                    
    End If
                
    Next
            
    End If
    End Sub
     
  7. derez

    derez Expert Licensed User

    I don't see here the problem.
    The fact that it happens after 19 times calls for memory problem.

    A comment:
    Code:
    If Gesendet.GetSimple1(Gesendet.ListKeys.Get(i),0)<>Null AND Gesendet.GetSimple1(Gesendet.ListKeys.Get(i),0)="False" Then
    The first part is covered by the second, so it is redundant:
    Code:
    If Gesendet.GetSimple1(Gesendet.ListKeys.Get(i),0)="False" Then
     
  8. schimanski

    schimanski Well-Known Member Licensed User

    Ok...thanks. I will try something more...
    But when it is a memory-problem, it would be raised by the lines above. Before this code, i had two maps to hold the same keys and values in the identical subs and that was no problem.
     
    Last edited: Feb 20, 2015
  9. derez

    derez Expert Licensed User

    The code above shows use of just index 0 so there is no need of this class, if you do more with it and want help you must show it.
    I believe you are loading data, not only checking its existence.
     
  10. schimanski

    schimanski Well-Known Member Licensed User

    Thank for help!

    There is no need to show more code, derez. The following sample-code is enough to raise the exception after about 10 seconds:

    Code:
    Sub Process_Globals
        
    Private UploadTimer As Timer
        
    Dim Gesendet As KeyValues
    End Sub

    Sub Globals
       
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
        
    If Gesendet.IsInitialized=False Then Gesendet.Initialize(File.DirInternal, "Gesendet.eis"2)   
        UploadTimer.Initialize(
    "UploadTimer"100)
    End Sub

    Sub Activity_Resume
        Gesendet.PutSimple1(
    "A1"0"True")
        Gesendet.PutSimple1(
    "A2"0"False")
        Gesendet.PutSimple1(
    "A1"1"True")
        Gesendet.PutSimple1(
    "A2"1"False")

        UploadTimer.Enabled=
    True
    End Sub

    Sub UploadTimer_Tick

        
    Log ("Timer raised!")
       
        
    If Gesendet.IsInitialized=False Then Gesendet.Initialize(File.DirInternal, "Gesendet.eis"2)
        
    Log(Gesendet.ListKeys.Size)
        
    If Gesendet.ListKeys.Size>0 Then
            
    For i=0 To Gesendet.ListKeys.Size-1
                
    If Gesendet.GetSimple1(Gesendet.ListKeys.Get(i),0)="False" Then
        
                
    End If
            
    Next
        
    End If
    End Sub
    I have mentioned, that the exception comes, after the timer is raised 86 times with the code
    Code:
    If Gesendet.GetSimple1(Gesendet.ListKeys.Get(i),0)<>Null AND Gesendet.GetSimple1(Gesendet.ListKeys.Get(i),0)="False" Then
    and after 126 times with the line
    Code:
    if Gesendet.GetSimple1(Gesendet.ListKeys.Get(i),0)="False" Then

    Code:
    android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=609 (# cursors opened by this proc=609)
        at android.database.CursorWindow.<init>(CursorWindow.java:
    108)
        at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:
    198)
        at android.database.sqlite.SQLiteCursor.clearOrCreateWindow(SQLiteCursor.java:
    301)
        at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:
    139)
        at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:
    133)
        at anywheresoftware.b4a.sql.SQL$CursorWrapper.getRowCount(
    SQL.java:313)
        at b4a.example.keyvalues._vvvv1(keyvalues.java:
    464)
        at b4a.example.main._uploadtimer_tick(main.java:
    386)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:
    372)
        at anywheresoftware.b4a.BA.raiseEvent2(BA.java:
    187)
        at anywheresoftware.b4a.objects.Timer$TickTack.run(
    Timer.java:105)
        at android.os.Handler.handleCallback(Handler.java:
    739)
        at android.os.Handler.dispatchMessage(Handler.java:
    95)
        at android.os.Looper.loop(Looper.java:
    145)
        at android.app.ActivityThread.main(ActivityThread.java:
    5834)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:
    372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:
    1388)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:
    1183)
    android.database.CursorWindowAllocationException: 
    Cursor window allocation of 2048 kb failed. # Open Cursors=609 (# cursors opened by this proc=609)
    I'm using a samsung galaxy S5....
     
  11. schimanski

    schimanski Well-Known Member Licensed User

    O.k, I have tesed the same code with Erel's keyvaluestore-class. It's the same problem:(
     
    Last edited: Feb 21, 2015
  12. derez

    derez Expert Licensed User

    I've made some changes in your sub and with this on nexus 5 emulator it runs up to 987 times while with your code it went up to 329.
    Code:
    Sub UploadTimer_Tick
        count = count + 
    1
        
    Log ("Timer raised! " & count)
      
        
    If Gesendet.IsInitialized = False Then
            Gesendet.Initialize(
    File.DirInternal, "Gesendet.eis"2)
        
    End If

        
    For Each k As String In Gesendet.ListKeys
            
    If Gesendet.GetSimple1(k,0)="False" Then

            
    End If
        
    Next

    End Sub
    It is a problem of memory-cpu relations in the device, like the memory is saying to itself:
     
  13. schimanski

    schimanski Well-Known Member Licensed User

    Thanks for that! Now i understand the problem. With your changes, it is much better, but it seems, that a keyvaluestore is not the best solution for a 'timer-check'. Here it is better to use a map....
     
  14. Peter Simpson

    Peter Simpson Expert Licensed User

    Hello,
    I don't actually need this solution, but I spotted it and just thought that I would give it a go to see what it's like. Anyway I ran your code(KeyValues_1.1.zip) without making any changes to it and BOOOOOOM.

    Code:
    Error saving object: (SQLiteException) android.database.sqlite.SQLiteException: table main has 2 columns but 3 values were supplied (code 1): , while compiling: INSERT INTO main VALUES(?,?,?)
    Here is the whole log in full:
    Code:
    ** Activity (main) Create, isFirst = true **
    ** 
    Activity (main) Resume **
    Error saving object: (SQLiteException) android.database.sqlite.SQLiteException: table main has 
    2 columns but 3 values were supplied (code 1): , while compiling: INSERT INTO main VALUES(?,?,?)
    Error occurred on line: 
    44 (main)
    java.lang.NullPointerException
        at b4a.example.main._activity_resume(main.java:
    414)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:
    515)
        at anywheresoftware.b4a.shell.Shell.runMethod(
    Shell.java:636)
        at anywheresoftware.b4a.shell.Shell.raiseEventImpl(
    Shell.java:305)
        at anywheresoftware.b4a.shell.Shell.raiseEvent(
    Shell.java:238)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:
    515)
        at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:
    121)
        at anywheresoftware.b4a.BA.raiseEvent(BA.java:
    171)
        at b4a.example.main.afterFirstLayout(main.java:
    106)
        at b4a.example.main.access$
    100(main.java:17)
        at b4a.example.main$WaitForLayout.run(main.java:
    78)
        at android.os.Handler.handleCallback(Handler.java:
    733)
        at android.os.Handler.dispatchMessage(Handler.java:
    95)
        at android.os.Looper.loop(Looper.java:
    157)
        at android.app.ActivityThread.main(ActivityThread.java:
    5356)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:
    515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:
    1265)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:
    1081)
        at dalvik.system.NativeStart.main(Native Method)
     
  15. derez

    derez Expert Licensed User

    I downloaded it and it runs fine. I read in your post:
    in the program line 44 is
    Code:
    Log(res(0) & DateTime.Time(res(1)))
    This line has nothing to do with inserting data, so there must be something you have changed that causes it to fail.
    will you be so kind as to give some more details ?
     
  16. derez

    derez Expert Licensed User

    Rolling it in my head while walking I thought I found it but no. May be ver 4.3 added something so the row in your file is
    Code:
    kvs.PutSimple2("Time",val)
    I have followed it with no DB existence and it works ok. The three values are
    key - "Time"
    val(0) - "The Time now: "
    val(1) - DateTime.Now
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice