Save mulitple settings (different profiles)

moster67

Expert
Licensed User
Longtime User
So far one of my app has saved decoder-settings using MAP as per the following structure:

Decoder IP=192.168.1.8
UserName=myUserName
Password=myPassword
etc

Now I want to give the user the possibility to save settings relative to more than one decoder and thus allow multiple decoders in this app. This mean I will end up with decoder-settings as follows:

NameOfDecoder=Decoder1 (to distinguish from other decoders)
Decoder IP=192.168.1.8
UserName=myUserName
Password=myPassword
etc

NameOfDecoder=Decoder2
Decoder IP=192.168.1.9
UserName=myUserName
Password=myPassword
etc

NameOfDecoder=Decoder3
Decoder IP=192.168.1.10
UserName=myUserName
Password=myPassword
etc

Maybe in this case, the usage of MAP is not the best one.

How would you handle the saving of mutilple profiles (in my case, more than one decoder)? I guess it must be structured somehow. However, I don't want to use any database for this.
 

lagore

Active Member
Licensed User
Longtime User
Hi,
Maps will work great just put a variable after the map 'key'
B4X:
Dim myMap As Map
   Dim thisDecoder, thisUserName, thisPassword As String
   Dim Decoders As Int      'number of decoders
   
   For i = 0 To Decoders - 1
      myMap.Put("Decoder" + i,thisDecoder);
         myMap.Put("UserName" + i,thisUserName);
         myMap.Put("Password" + i,thisPassword);
      'add in code to change to the next decoder
   Next
   
   'to reference
   Dim decoderIP, decoderUsername, decoderPassword As String
   
   i = 0      'get details of first decoder in the sequence
   
   decoderIP = myMap.get("Decoder" & i)
   decoderUsername = myMap.get("UserName" & i)
   decoderPassword = myMap.get("Password" & i)
I have done this myself and it is fine.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Another option is to create a custom type:
B4X:
Type DecoderSettings (Name As String, IP As String, ...)

You can then create a map with the decoders names as keys and the values are of type DecoderSettings.

You should use RandomAccessFile.WriteObject / ReadObject to write the map to a file. Note that the file will not be a text file.
 
Upvote 0

moster67

Expert
Licensed User
Longtime User
Thanks both of you for your ideas.

I think Lagore's example is probably something I can implement although I still would need to study a lot how to do it. However, I am curious as to Erel's suggestion as I have never used Types and RandomAccessFile before. I didn't find much information (in particular examples) and I can't really understand how to use it.

Here is an example I have tried to get it working but I can' really get it working. I have problems with Map-values being overwritten although the Keys are different. In addition, since I ran the example many times, I expected that the file where I save the data, settings.dat, to contain more data. I am not really sure how to use Type as well.

Anyone who cares to help me to get Erel's idea working?

Here is the example-project I tried (requires RandomAccessFile-library):

B4X:
'Activity module
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.
   
   Type DecoderSettings ( _
    Name           As String,     _
    IPAddress      As String,    _
    Port           As String)
   Dim Decoders As DecoderSettings
End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.

   Dim rac As RandomAccessFile
   Dim Map1 As Map
End Sub

Sub Activity_Create(FirstTime As Boolean)
   
   Decoders.Initialize
   Map1.Initialize
    
   InsertAndSaveSettings
   ReadSettings
   
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub
Sub InsertAndSaveSettings

   'INSERT AND SAVE SOME DATA (1st time)
   
   Decoders.Name="Decoder1"
   Decoders.IPAddress="192.168.1.1"
   Decoders.Port="80"
   
   Map1.Put(Decoders.Name,Decoders)

   For i = 0 To Map1.Size -1
      Log(Map1.GetKeyAt(i) & " - " & Map1.GetValueAt(i))
   Next
   
   'LOG is: Decoder1 - [IPAddress=192.168.1.1, Port=80, Name=Decoder1, IsInitialized=true]
   
   rac.Initialize(File.DirInternal,"settings.dat",False)
   rac.WriteObject(Map1,True,rac.CurrentPosition)
   rac.Close
   

   'INSERT SOME MORE DATA AND SAVE (2nd time)
   
   Decoders.Name="Decoder2"
   Decoders.IPAddress="192.168.1.2"
   Decoders.Port="8888"
   
   Map1.Put(Decoders.Name,Decoders)
   
   For i = 0 To Map1.Size -1
      Log(Map1.GetKeyAt(i) & " - " & Map1.GetValueAt(i))
   Next
   
   'LOG Is: Decoder1 - [IPAddress=192.168.1.2, Port=8888, Name=Decoder2, IsInitialized=True]
   '       Decoder2 - [IPAddress=192.168.1.2, Port=8888, Name=Decoder2, IsInitialized=True]
   ' where the Keys are different from eachother but the values are the same. Seems like it
   ' saving only the data inserted the second time
   
   rac.Initialize(File.DirInternal,"settings.dat",False)

   rac.WriteObject(Map1,True,rac.CurrentPosition)
   rac.Close
   
End Sub
Sub ReadSettings
   
   'LET US READ THE DATA WHICH WAS SAVED
   
   rac.Initialize(File.DirInternal,"settings.dat",False)

   Dim map2 As Map
   map2.Initialize
   
   map2=rac.ReadObject(rac.CurrentPosition)

   For i = 0 To map2.Size -1
      Log(map2.GetKeyAt(i) & " - " & map2.GetValueAt(i))
   Next
   
   'LOG Is: Decoder1 - [IPAddress=192.168.1.2, Port=8888, Name=Decoder2, IsInitialized=True]
   '       Decoder2 - [IPAddress=192.168.1.2, Port=8888, Name=Decoder2, IsInitialized=True]
   ' where the Keys are different from eachother but the values are the same. Seems like it
   ' saving only the data inserted the second time
   '
   '??????? - I expected more data in "settings.dat" since I have run this example many times
    rac.Close
   
End Sub
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Here:
B4X:
'Activity module
Sub Process_Globals
    Type DecoderSettings ( _
       Name           As String,     _
       IPAddress      As String,    _
       Port           As String)
   Dim raf As RandomAccessFile
    Dim Decoders As Map
End Sub

Sub Globals

End Sub

Sub Activity_Create(FirstTime As Boolean)
    If FirstTime Then
       Decoders.Initialize
      raf.Initialize(File.DirInternal,"settings.dat",False)
      If raf.Size > 0 Then
         'read the previous saved settings
         ReadSettings
        End If
   End If
   
   
    InsertAndSaveSettings
    ReadSettings
    
End Sub


Sub InsertAndSaveSettings

    'INSERT AND SAVE SOME DATA (1st time)
    Dim Decoder As DecoderSettings
    Decoder.Name="Decoder1"
    Decoder.IPAddress="192.168.1.1"
    Decoder.Port="80"
    
    Decoders.Put(Decoder.Name,Decoder)
    
    raf.WriteObject(Decoders,True,0) 'always use position 0. We only hold a single object in this case so we can start from the beginning.
    raf.Flush 'Not realy requied here. Better to call it when you finish writing
    

    'INSERT SOME MORE DATA AND SAVE (2nd time)
    Dim Decoder As DecoderSettings 'If you don't call Dim again then you are overwriting the previous object
    Decoder.Name="Decoder2"
    Decoder.IPAddress="192.168.1.2"
    Decoder.Port="8888"
    
    Decoders.Put(Decoder.Name,Decoder)
    raf.WriteObject(Decoders, True, 0)
    
End Sub

Sub ReadSettings
    Decoders = raf.ReadObject(0) 'always 0 (single object)
    For i = 0 To Decoders.Size -1
        Log(Decoders.GetKeyAt(i) & " - " & Decoders.GetValueAt(i))
    Next
End Sub

I prefer to keep the random access file always open. As we are only saving a single object to the file, the object is written and later read from position 0.
 
Upvote 0

moster67

Expert
Licensed User
Longtime User
Thank you so much Erel. It is easy to tell an experienced programmer (professional or amateur) from a spaghetti-programmer like me

Your example made everything so much clearer and I like this approach. I added some extra functions to the code and everything seems to work. Now I will see if I can use it as a code-module.

Here is my updated code (in case it might be of interest for someone else)

B4X:
Sub Process_Globals
    Type DecoderSettings ( _
        Name           As String,     _
        IPAddress      As String,    _
        Port           As String)
    Dim raf As RandomAccessFile
    Dim Decoders As Map
End Sub

Sub Globals

End Sub

Sub Activity_Create(FirstTime As Boolean)
    If FirstTime Then
        Decoders.Initialize
        raf.Initialize(File.DirInternal,"settings1.dat",False)
        If raf.Size > 0 Then
            'read the previous saved settings
            ReadSettings
         End If
    End If
    
    InsertAndSaveSettings
    ReadSettings 'check result of InsertAndSaveSettings
   SearchAndModify
   ReadSettings 'check result of SearchAndModify
   SearchAndDelete
    ReadSettings 'check result of SearchAndDelete
   AddMoreDecoders 
   ReadSettings 'check result of AddMoreDecoders
   DeleteALL
   ReadSettings 'check result of DeleteALL
   AddMoreDecoders
   ReadSettings 'check result of AddMoreDecoders
End Sub


Sub InsertAndSaveSettings

    'INSERT AND SAVE SOME DATA (1st time)
    Dim Decoder As DecoderSettings
    Decoder.Name="Decoder1"
    Decoder.IPAddress="192.168.1.1"
    Decoder.Port="80"
    
    Decoders.Put(Decoder.Name,Decoder)
    
    raf.WriteObject(Decoders,True,0) 'always use position 0. We only hold a single object in this case so we can start from the beginning.
    raf.Flush 'Not realy requied here. Better to call it when you finish writing
    

    'INSERT SOME MORE DATA AND SAVE (2nd time)
    Dim Decoder As DecoderSettings 'If you don't call Dim again then you are overwriting the previous object
    Decoder.Name="Decoder2"
    Decoder.IPAddress="192.168.1.2"
    Decoder.Port="8888"
    
    Decoders.Put(Decoder.Name,Decoder)
    raf.WriteObject(Decoders, True, 0)
    
End Sub

Sub ReadSettings
    Dim Decoder As DecoderSettings
    Decoders = raf.ReadObject(0) 'always 0 (single object)
   
   Log("Map-size is : " & Decoders.Size)
   
    For i = 0 To Decoders.Size -1
        Log(Decoders.GetKeyAt(i) & " - " & Decoders.GetValueAt(i))
      Decoder=Decoders.GetValueAt(i)
      Log(Decoder.Name)
      Log(Decoder.IPAddress)
      Log(Decoder.Port)
    Next
End Sub
Sub SearchAndDelete
   'search for decoder-port 8888 and delete corresponding  record
   
   Dim Decoder As DecoderSettings
   Decoders=raf.ReadObject(0)
   For i = 0 To Decoders.Size -1
   Decoder=Decoders.GetValueAt(i)
      If Decoder.Port="8888" Then
      Decoders.Remove(Decoder.Name)
      End If
   Next
   
'   Decoders.Put(Decoder.Name,Decoder)
    raf.WriteObject(Decoders, True, 0)
   

End Sub
Sub SearchAndModify
   'search for decoder-key with IP 192.168.1.2 then delete it and create a new identical one with new ip-address as 192.168.1.3
   Dim decName,decPort As String 'placeholders
   Dim Decoder As DecoderSettings
   Decoders=raf.ReadObject(0)
   
   For i = 0 To Decoders.Size -1
   decoder=Decoders.GetValueAt(i)
      If decoder.IPAddress="192.168.1.2" Then
      decName=decoder.Name
      decPort="8888"
      Decoders.Remove(decoder.Name)
      End If
   Next
   
   Dim decoder As DecoderSettings
      decoder.Name=decName
      decoder.IPAddress="192.168.1.3"
      decoder.Port=decPort

   Decoders.Put(decoder.Name,decoder)
    raf.WriteObject(Decoders, True, 0)

End Sub
Sub AddMoreDecoders
   'add two more decoders/data
   
   Dim decoder As DecoderSettings
      decoder.Name="Decoder3"
      decoder.IPAddress="192.168.1.5"
      decoder.Port="8999"

   Decoders.Put(decoder.Name,decoder)
    raf.WriteObject(Decoders, True, 0)
   raf.Flush
   
   Dim decoder As DecoderSettings
      decoder.Name="Decoder4"
      decoder.IPAddress="192.168.1.9"
      decoder.Port="9999"

   Decoders.Put(decoder.Name,decoder)
    raf.WriteObject(Decoders, True, 0)
   raf.Flush
   
End Sub
Sub DeleteALL
   Decoders.Clear
   raf.WriteObject(Decoders, True, 0)
   raf.Flush
End Sub
 
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…