B4J Library [B4X] KVS2 / KeyValueStore 2 - Simple & Powerful Local Datastore

Status
Not open for further replies.
Recommended to use the newer b4xlib: https://www.b4x.com/android/forum/threads/b4x-kvs2-keyvaluestore2-library.120234/
KeyValueStore is a persistent key/value based data store. It is similar to the useful Map collection, however unlike Map which stores the data in memory, KVS stores the data in a database. This means that you don't need to worry about losing data or saving the state when the program ends.

This version replaces the older version. It is not backwards compatible. You cannot use it with databases created with the previous version.

The main differences between v2 and v1:
The new version is based on B4XSerializator to serialize the values and on B4XCipher to encrypt it.
This means that the data can be shared between B4A, B4J and B4i. For example you can create the data store in B4J and embed it in your mobile app.
B4XSerializator is also faster and simpler to use.

Using KVS is similar to using a Map. You initialize it once (use the Starter service in B4A) and then you can put or get items with Put, Get or GetDefault methods.
You can use PutEncrypted to encrypt the value before it is stored. Use GetEncrypted to get an encrypted value.
If you want to put bitmaps then use PutBitmap and GetBitmap.

The supported types of objects are:

Lists, Maps, Strings, primitives (numbers), user defined types and arrays (only arrays of bytes and arrays of objects are supported).
Custom types should be declared in the main module.
Including combinations of these types (a list that holds maps for example).

KeyValueStore depends on the following libraries: SQL, RandomAccessFile and B4XEncryption (iEncryption on B4i).
Note that in B4J you need to download the bouncy castle jar and add the following two lines to the main module:
B4X:
#AdditionalJar: sqlite-jdbc-3.7.2
#AdditionalJar: bcprov-jdk15on-154


A B4A example is attached. The class module is compatible with B4A, B4J and B4i.

Tip: Check CloudKVS for an auto-synchronizing solution: https://www.b4x.com/android/forum/threads/b4x-cloudkvs-synchronized-key-value-store.63536/#content

Updates:

- V2.20 - Adds support for GetMapAsync and PutMapAsync. These methods allow to asynchronously insert or retrieve multiple items.
Examples:
B4X:
'getting all items:
Wait For (Starter.kvs.GetMapAsync(Starter.kvs.ListKeys)) Complete (Result As Map)
Log(Result)
'getting specific items:
Wait For (Starter.kvs.GetMapAsync(Array("Key1", "Key2", "Key3")) Complete (Result As Map)
Log(Result)

Note that starting from B4A v8.0 KeyValueStore2 is included as an internal library.
 

Attachments

  • B4A_KVS2.zip
    9.8 KB · Views: 2,886
  • KeyValueStore.bas
    4.8 KB · Views: 2,569
Last edited:

leitor79

Active Member
Licensed User
Longtime User
Hi,

I have a question: how is that v2 is faster than 1.01, being the case that 1.01 uses sql1.2 and v2 uses sql 1.3, which uses resulsets, that aren't more powerful than cursors? It would be true to say that v1.01 is better for certain type of data? (for example, if I only store text and numbers and not other type of objects)

Regards,
 

jaraiza

Active Member
Licensed User
Longtime User
Sorry if I ask something obvious, but I haven't find anything related. The "string" should be unique between applications, or the name can conflict with another app?

I mean, can I use 'Starter.kvs.Put("time", DateTime.Now)' in all my apps, or should I use 'Starter.kvs.Put("app1_time", DateTime.Now)' and 'app2_Starter.kvs.Put("time", DateTime.Now)' in another app?

Thanks!
 

vk7krj

Member
Licensed User
Hi, a rank beginner here. I downloaded the KeyValueStore zip file for B4A from the link on the first page of this thread, unzipped it and copied AndroidManifest.xml to the libraries folder, but the help says to copy the .jar file as well- but there isn't one in the zip file. When I try to refresh the libraries, it says it can't find the jar file- reasonable, as there isn't one- where can I find the associated .jar file for this library please?

Thanks, Ken.
 

DonManfred

Expert
Licensed User
Longtime User
KVS is a CLASS Module

KeyValueStore.bas

You need to copy it to your project folder and add the module
 

vk7krj

Member
Licensed User
Hi Again, yet more stuff I don't understand- it seems I have a lot of trouble with the concepts of Object Oriented programming.

I am now getting the error-

Error description: Array expected.
Occurred on line: 49
Fuel_datastore.Initialize(File.DirApp, "Fuel_datastore")
Word: (

The code is here-

B4X:
Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    If StateManager.RestoreState(Activity, "Main", 0) = False Then
        Fuel_datastore.Initialize(File.DirApp, "Fuel_datastore")
        current_fuel = 0
        odo = 0
        old_odo = 0
        total_fuel = 0
        total_odo = 0
        start_odo = 0
        oa_consumption = 0
        current_consumption = 0
        Fuel_datastore.PutSimple("oa_consumption", oa_consumption)
        Fuel_datastore.PutSimple("current_consumption", current_consumption)
        Fuel_datastore.PutSimple("total_fuel", total_fuel)
        Fuel_datastore.PutSimple("start_odo", start_odo)
        Fuel_datastore.PutSimple("old_odo", old_odo)
    End If
    Activity.LoadLayout("fuellayout")
        OdometerEntry.Text = "0"
        FuelEntry.Text = "0"
    Calculate_click

I have also declared Fuel_datastore As KeyValueStore in Process_Globals and have searched the forum & read the tutorials and cannot find a solution (or perhaps didn't recognise it?) - please, what am I doing wrong?

Without the KeyValueStore class, the app does exactly what I want it to, I just don't have persistent data storage.

Thanks, Ken.
 

panagiotisden2

Active Member
Licensed User
Longtime User
Hello, I just received this log from a user
It seems that kvs caused a force close
I don't have problems in a lot of devices I tested my app. Any help here?

B4X:
Java.lang.RuntimeException: Unable to start service com.orionapps.zerodot.bglistener@420c0cf0 with Intent { cmp=com.orionapps.zerodot/.bglistener }: java.lang.RuntimeException: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2885)
    at android.app.ActivityThread.access$2100(ActivityThread.java:151)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1418)
    at android.os.Handler.dispatchMessage(Handler.java:110)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:5299)
    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:829)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:645)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:206)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
    at com.orionapps.zerodot.bglistener.handleStart(bglistener.java:101)
    at com.orionapps.zerodot.bglistener.onStartCommand(bglistener.java:69)
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2868)
    ... 10 more
Caused by: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
    at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
    at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
    at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
    at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
    at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
    at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
    at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:829)
    at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:814)
    at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:709)
    at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:684)
    at anywheresoftware.b4a.sql.SQL.Initialize(SQL.java:37)
    at com.orionapps.zerodot.keyvaluestore._initialize(keyvaluestore.java:156)
    at com.orionapps.zerodot.bglistener._service_start(bglistener.java:519)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
    ... 14 more
 

ilan

Expert
Licensed User
Longtime User
Umm default kvs location? I did not change anything I just used the example

cloudkvs? https://www.b4x.com:51041/cloudkvs?

You can use this link for the ServerUrl during development:
https://www.b4x.com:51041/cloudkvs
Note that the messages are limited to 100k and more importantly the database is deleted every few days. The clients will stop updating after the database is deleted. You can delete the local database (or uninstall and install the app again) for the clients to work again.
Remember to use unique ids for the user value.
 

Mahares

Expert
Licensed User
Longtime User
No, its a local db, kvs2 not cloudkvs
The below line located in most likely your Starter service module tells you where the kvs file is saved:
kvs.Initialize(File.DirDefaultExternal, "datastore2")
If you want it where you can more easily see it, you can save it here:
kvs.Initialize(File.DirRootExternal, "datastore2")
 

Wolfgang Trageiser

Member
Licensed User
Longtime User
can i use 3 or more KVS2-objects like:

Sub Process_Globals
Public kvs_systemdata As KeyValueStore
Public kvs_userdata As KeyValueStore
Public kvs_defaultdata As KeyValueStore
End Sub
 
Status
Not open for further replies.
Top