Android Question Map within map, saving to file and reading from file?

Daica

Active Member
Licensed User
Let's say I have the following:
B4X:
Sub InsertAndSave()

    If SuperMap.IsInitialized = False Then
        SuperMap.Initialize
    End If

    Dim Item1 As Map
    Item1.Initialize
    Item1.Put("Key1", "Item1 Value1")
    Item1.Put("Key2", "Item1 Value2")
    Item1.Put("Key3", "Item1 Value3")
    SuperMap.Put(SuperMap.Size + 1, Item1 )

    Dim Item2 As Map
    Item2.Initialize
    Item2.Put("Key1", "Item2 Value1")
    Item2.Put("Key2", "Item2 Value2")
    Item2.Put("Key3", "Item2 Value3")
    SuperMap.Put(SuperMap.Size + 1, Item2 )

    File.WriteMap(File.DirInternal, "SuperMap", SuperMap)
End Sub

Once I insert the 2 maps (Item1, Item2) into SuperMap, I write the SuperMap to a file.

When I go to load the SuperMap file, would it be all mess up?
B4X:
Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")

 
    If File.Exists(File.DirInternal, "SuperMap") Then
        SuperMap.Initialize
        SuperMap = File.ReadMap(File.DirInternal, "SuperMap")
     
        Dim m As Map
        m.Initialize
        m = SuperMap.Get(1)
     
        MsgboxAsync(m.Get("Key1"), "")
     
    End If

End Sub

What should I use/do if I want to store a map within a map and be able to save/read that map into a file?
 
Last edited:

mangojack

Expert
Licensed User
Longtime User
File.WriteMap(...) converts all values to Strings , so it is not a good solution for storing multiple maps.

Switch to KeyValueStore .. It is proving to be a very simple and powerful option ... (storing maps & images etc)

B4X:
Private KVS As KeyValueStore

    KVS.Initialize(File.DirInternal, "datastore")

    Dim Item1 As Map
    Item1.Initialize
    Item1.Put("Key1", "Item1 Value1")
    '...........................
    KVS.Put("Map1", Item1 )

    Dim Item2 As Map
    '............................
    KVS.Put("Map2", Item2 )


B4X:
    Dim m As Map = KVS.Get("Map1")   
    Log(m.Get("Key1"))

I am unsure if using KVS / Map size is a good idea to be used as a 'Key'

PS: Don't use MsgBox to process debug comments. Use Log("....")
 
Last edited:
Upvote 0

Mahares

Expert
Licensed User
Longtime User
What should I use/do if I want to store a map within a map and be able to save/read that map into a file?
Another nice option in addition to the good one mj presented is: B4XSerializator which uses the internal library RandomAccessFile. If you need an example, I can come up with one.

am unsure if using KVS / Map size is a good idea to be used as a 'Key
You are correct. One he can do since the key must be a string:
B4X:
Dim n As String =SuperMap.Size+1
    SuperMap.Put(n, Item1 )
.
.
.
B4X:
Dim n As String =SuperMap.Size+1
    SuperMap.Put(n, Item2 )
 
Upvote 0

Daica

Active Member
Licensed User
Another nice option in addition to the good one mj presented is: B4XSerializator which uses the internal library RandomAccessFile. If you need an example, I can come up with one.

I would very much appreciate an example, or a link to one :)
 
Upvote 0

KMatle

Expert
Licensed User
Longtime User
As you have items, why not adding them (the maps) to a list? Beneath that you can convert that list/map into a JSON string with the JSON-generator by

B4X:
JsonList.Initialize
    JsonList.Add(aMap) 'add more maps if needed
    JsonGenerator.Initialize2(JsonList)
    Dim JSONString As String = JsonGenerator.ToString

an save it as a simple string.

I use RandomAccesFile to save lists and maps directly:

B4X:
Dim m As Map
    m.initialize
    m.Put("a",PDFPathTF.Text)
    m.Put("b",PDFPathCopy2TF.Text)
    m.Put("c",EmailDBPathTF.Text)
    m.Put("d",MWSTTF.Text)
    m.Put("e",InkassoPathTF.Text)
    
    
    Dim RAFOut As RandomAccessFile
    RAFOut.Initialize(File.DirApp & "/OPTIONS/","options.dat",False) 'B4J path. Change it for B4A
    RAFOut.WriteB4XObject(m,0)
    RAFOut.Close

B4X:
Dim m As Map
        Dim RAFIn As RandomAccessFile
        RAFIn.Initialize(File.DirApp & "/OPTIONS/","options.dat",True)
        m=RAFIn.ReadB4XObject(0)
        RAFIn.Close
 
Upvote 0

Daica

Active Member
Licensed User
If you are all set with @KMatle 's code, that is great. If you still want to see B4XSerializator or Json in action to your application please come back.

I would like to see both ways, for my own understanding and for others as well who are like me, thank you !
 
Upvote 0

cklester

Well-Known Member
Licensed User
You are correct. One he can do since the key must be a string:
B4X:
Dim n As String =SuperMap.Size+1
    SuperMap.Put(n, Item1 )

The reason he suggested not using the size is because the size can shrink and you'll risk overwriting data you don't want overwritten. Turning it into a string doesn't solve that problem. And keys don't have to be strings.

The only safe way to use the size of the map as a key is if you never remove an item from the map. If you end up needing to "remove" something in this case, you'll want to just assign a "DELETED" flag to the map item's data somehow, or have a separate index of deleted records.
 
Upvote 0

Mahares

Expert
Licensed User
Longtime User
Turning it into a string doesn't solve
Did you run the project. Assuming he does not remove items, try to put this line: SuperMap.Put(SuperMap.Size+1, Item2 )
instead of these two lines:
B4X:
Dim n As String =SuperMap.Size+1
   SuperMap.Put(n, Item2 )
and run my project, it will crash for you.
 
Upvote 0

cklester

Well-Known Member
Licensed User
Did you run the project. Assuming he does not remove items, try to put this line: SuperMap.Put(SuperMap.Size+1, Item2 )
instead of these two lines:
B4X:
Dim n As String =SuperMap.Size+1
   SuperMap.Put(n, Item2 )
and run my project, it will crash for you.

No, I haven't run the project, but from my reading of the documentation for map, there's nothing stopping you from using a number as a key.

The documentation for map says, "The key should be a string or a number."

The project must be crashing for a reason other than the type of the key.
 
Upvote 0

Mahares

Expert
Licensed User
Longtime User
The project must be crashing for a reason other than the type of the key.
I know a key can be an object, but in this case I had to make it a string for it to work. It crashes when you read the map. Why don't you run it and see i for yourself and manage it and report back with a fix.
 
Upvote 0

Daica

Active Member
Licensed User
I know a key can be an object, but in this case I had to make it a string for it to work. It crashes when you read the map. Why don't you run it and see i for yourself and manage it and report back with a fix.

I ran your project, it works fine. I'm able to loop through the SuperMap and list whatever I want. I actually do need to delete the key once I read it, but using a For Loop causes an error because the key is being removed and the index changes.

B4X:
For Each k As String In SuperMap.Keys
    Dim m As Map = SuperMap.Get(k)
    Dim j As JSONGenerator
    j.Initialize(m)
    PostJsonToServer(j.ToString)
    SuperMap.Remove(k)
Next

This results in an error when removing the key. Is there a way to do it with
B4X:
For i = 0 To SuperMap.Size -1 To 0 Step - 1
Next
 
Upvote 0

Star-Dust

Expert
Licensed User
Longtime User
This is wrong it does not follow the syntax
B4X:
For i = 0 To SuperMap.Size -1 To 0 Step - 1

If anything this way
B4X:
For i = SuperMap.Size -1 To 0 Step - 1
    Dim m As Map = SuperMap.GetValueAt(I)
    Dim j As JSONGenerator
    j.Initialize(m)
    PostJsonToServer(j.ToString)
    SuperMap.Remove(SuperMap.GeKeyAt(I))
Next

But it is not recommended to do so
 
Last edited:
Upvote 0

Star-Dust

Expert
Licensed User
Longtime User
Its okay to use a deprecated method? I didn't want to use GetKeyAt since it says its deprecated, but this works 100%

B4X:
For i = SuperMap.Size -1 To 0 Step - 1
    SuperMap.Remove(SuperMap.GetKeyAt(i))
Next
I have already written that it should not be used. I specified that the syntax used in the for was wrong

B4X:
For i = 0 To SuperMap.Size -1 To 0 Step - 1 ' WRONG !!! 0 To Val to 0
 
Last edited:
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
What should I use/do if I want to store a map within a map and be able to save/read that map into a file?
Store
B4X:
    Dim m As Map
    m.Initialize
    m.Put("Test","Testvalue")
    
    Dim data As List ' Create a List to store in the Map
    data.Initialize
    data.Add("TestA")
    data.Add("TestB")
    data.Add("TestC")
    data.Add("TestD")
    m.Put("Data",data) ' Add the List to the Map
    
    Dim m2 As Map ' Create another Map to store in the 1st Map
    m2.Initialize
    m2.Put("Map2A","bla")
    
    m.Put("m2",m2) ' add the new map to the 1st Map
    

    Dim xser As B4XSerializator ' RandomAccessFile Lib
    Dim data2save() As Byte = xser.ConvertObjectToBytes(m)
    File.WriteBytes(File.DirInternal,"MapData.dat",data2save)

Read back the Data

B4X:
    Dim xser As B4XSerializator
    Dim loadeddata() As Byte = File.ReadBytes(File.DirInternal,"MapData.dat")
    Dim newm As Map = xser.ConvertBytesToObject(loadeddata)
 
Upvote 0

rbirago

Active Member
Licensed User
Longtime User
I often use nested maps/lists and when I want to save them I use writeB4XObject of the RandomAccessFile library. Try it
 
Upvote 0
Top