Android Tutorial KeyValueStore class - Simple and efficient key/value data store

Status
Not open for further replies.
KeyValueStore v2 is available here: https://www.b4x.com/android/forum/threads/b4x-keyvaluestore-2-simple-powerful-local-datastore.63633/

In many cases applications need to store all kinds of data.

Key / value data stores (sometimes referred as NoSQL) can offer an alternative to relational databases (SQL). The key / value store offers a simple functionality. It allows you to store all kinds of values, where each value is mapped to a key. Very similar to Maps (as well as Dictionary, Hashtable, HashMap...). The main difference is that the store is persisted in the file system.

KeyValueStore class uses an SQLite database to store and retrieve all kinds of values.

It uses RandomAccessFile.WriteObject or WriteEncryptedObject to save collections and user types.

Using KeyValueStore is similar to using a Map:
B4X:
Sub Process_Globals
   Private kvs As KeyValueStore
End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
      kvs.Initialize(File.DirDefaultExternal, "datastore")
   End If
   'put a "simple" value
   kvs.PutSimple("time", DateTime.Now)
   'fetch this value
   Log(DateTime.Time(kvs.GetSimple("time")))

   'put a Bitmap
   kvs.PutBitmap("bitmap1", LoadBitmap(File.DirAssets, "asteroids.png"))
   'fetch a bitmap
   Activity.SetBackgroundImage(kvs.GetBitmap("bitmap1"))

   'remove the bitmap from the store
   kvs.Remove("bitmap1")

   'add a collection
   Dim list1 As List
   list1.Initialize
   For i = 1 To 10
      list1.Add("Item #" & i)
   Next
   kvs.PutObject("list1", list1)

   'fetch the collection
   Dim list2 As List = kvs.GetObject("list1")
   Log(list2)
   'encrypt the list
   kvs.PutEncyptedObject("encrypted list", list1, "topsecret")
   Try
      'note that if you run this example in Debug then it will break on this call. Press F5 to continue...
      list2 = kvs.GetEncryptedObject("encrypted list", "wrong password")
   Catch
      Log("Wrong password!")
   End Try
   list2 = kvs.GetEncryptedObject("encrypted list", "topsecret")
   Log(list2)
End Sub

The public methods of KeyValueStore:
B4X:
'Puts a simple value in the store.
'Strings and number types are considered "simple" values.
Sub PutSimple(Key As String, Value As Object) As Boolean

'Puts an object in the store. This method uses RandomAccessFile.WriteObject to save the object in the store.
'It is capable of writing the following types of objects: Lists, Arrays, Maps, Strings, primitive types and user defined types.
'Combinations of these types are also supported. For example, a Map with several lists of arrays can be written.
'The element type inside a collection must be a String OR primitive Type.
Sub PutObject(Key As String, Value As Object) As Boolean

'Similar to PutObject. Encrypts the object before writing it. Note that you can use it to store "simple" types as well.
Sub PutEncyptedObject(Key As String, Value As Object, Password As String) As Boolean

'Puts a bitmap in the store.
Sub PutBitmap(Key As String, Value As Bitmap) As Boolean

'Reads the data from the input stream and saves it in the store.
Sub PutInputStream(Key As String, Value As InputStream) As Boolean

'Removes the key and value mapped to this key.
Sub Remove(Key As String)

'Returns a list with all the keys.
Sub ListKeys As List

'Tests whether a key is available in the store.
Sub ContainsKey(Key As String) As Boolean

'Deletes all data from the store.
Sub DeleteAll

'Returns a "simple" value. See PutSimple.
Sub GetSimple(Key As String) As String

'Returns an InputStream from the store. See PutInputStream.
Sub GetInputStream(Key As String) As InputStream

'Returns a bitmap from the store. See PutBitmap.
Sub GetBitmap(Key As String) As Bitmap

'Returns an object from the store. See PutObject.
Sub GetObject(Key As String) As Object

'Returns an encrypted object from the store. See PutEncryptedObject.
Sub GetEncryptedObject(Key As String, Password As String) As Object

'Closes the store.
Sub Close

So if you do not need the more advanced features of a relational database then KeyValueStore is your probably best solution for data persisting.

The class is included in the attached example. It depends on the SQL and RandomAccessFile libraries.

V1.01 - Fixes an issue with open cursors.
 

Attachments

  • KeyValueStore.zip
    10.7 KB · Views: 4,667
Last edited:

BPak

Active Member
Licensed User
Longtime User
** Activity (main) Create, isFirst = true **
02:25:29
(ArrayList) [Item #1, Item #2, Item #3, Item #4, Item #5, Item #6, Item #7, Item #8, Item #9, Item #10]
Wrong password!
(ArrayList) [Item #1, Item #2, Item #3, Item #4, Item #5, Item #6, Item #7, Item #8, Item #9, Item #10]
** Activity (main) Resume **

I have Version 2.50 - Core 2.46 - RandomAccessFile 1.31 - SQL 1.20
and running in RELEASE get the Log of "Wrong Password". Yet the program runs and prints out all the Logs...
 

corwin42

Expert
Licensed User
Longtime User
If you carefully look at the example you will see that this is correct:

B4X:
    kvs.PutEncyptedObject("encrypted list", list1, "topsecret")
    Try
        'note that if you run this example in Debug then it will break on this call. Press F5 to continue...
        list2 = kvs.GetEncryptedObject("encrypted list", "wrong password")
    Catch
        Log("Wrong password!")
    End Try
    list2 = kvs.GetEncryptedObject("encrypted list", "topsecret")

The example tries to get the encrypted list with the password "wrong password" first and then tries with the correct password.
 

bluedude

Well-Known Member
Licensed User
Longtime User
Avoiding exposing some unique API keys in my app.

Hi Erel,

I would like to use the keyvalue store but I need to store some information into it outside my app. The reason for this is secret API keys that are used for the backend.

So I don't want to store the apikey in the app. code, any way to do this by using the keyvalue store? I assume it is just an SQLLite database?

Cheers,
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
KeyValueStore uses a regular SQLite database to store the data.

The simplest solution is to create a program that takes the keys and writes them to a store. Then use File.Copy to copy the file from File.DirInternalCache to the sd card.

The store file can be added to other projects (copy the file from File.DirAssets to File.DirInternalCache if it isn't already there).
 
D

Deleted member 103

Guest
Thank you!
This is precisely the class which I need in my new app.
:sign0098:
 

IanMc

Well-Known Member
Licensed User
Longtime User
I second that! Brilliant!

:sign0142:

I wouldnt' mind a bit of help though.

I need to persist a couple of lists.

In the example you save a list but then you load that list again but to a new list.

How would you save a list and then load it back again? The same list?
 
Last edited:

IanMc

Well-Known Member
Licensed User
Longtime User
Ah, ok, sorry to be so dim :)

So...
B4X:
Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
   Dim ListNames As List 
   ListNames.Initialize
End Sub

Sub Activity_Create(FirstTime As Boolean)
   'Do not forget to load the layout file created with the visual designer. For example:
   Activity.LoadLayout("main")
Dim ListNames2 As List = Main.kvs.GetObject("Names")
ListNames = ListNames2


End Sub

Something like that?
 

IanMc

Well-Known Member
Licensed User
Longtime User
Thanks Erel!

I've been having a play with KeyValueStore, its really good!

I can see this becoming a valuable tool in my toolbox.

Cheers!

:)
 

dgoss

Member
Licensed User
Longtime User
can keyvaluestore be manually edited, only ask cause i need to change a wrong value. its sposed to be in defaultexternal under "datastore" but dont see it:sign0104:
 

Quaki

Member
Licensed User
Longtime User
Hi
I'm trying to do this
The simplest solution is to create a program that takes the keys and writes them to a store. Then use File.Copy to copy the file from File.DirInternalCache to the sd card.

The store file can be added to other projects (copy the file from File.DirAssets to File.DirInternalCache if it isn't already there).
But I dont know how :( Erel could you write short sample how to export this file on the example from post one and then import it to other aplication
Quaki
 

Quaki

Member
Licensed User
Longtime User
Hi
Yes thats exactly what I want to do I even create something like this
B4X:
Sub Process_Globals
Private kvs As KeyValueStore
Dim al As String
Dim al1 As String      
Dim al2 As String
Dim al3 As String


End Sub

Sub Globals

End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
      kvs.Initialize(File.DirDefaultExternal, "datastore")
   End If
   
   al = "0"
   al1 = "0"
   al2 = "0"
   al3 = "0"
   
   
   kvs.PutSimple("al", "al")
   kvs.PutSimple("al1", "al1")
   kvs.PutSimple("al2", "al2")
    kvs.PutSimple("al3", "al3")
    

File.Copy(??????)


End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)
but I do not know what shoud be in place of (????) to export file into Sd card or any other folder and how to import file before the target aplication starts (or how to load file on first start of target aplication )
Quaki
 
Last edited:
Status
Not open for further replies.
Top