Android Question Map of Type Reading Problem

Midimaster

Active Member
Licensed User
I have a strange behavior in my code, but I cannot see the bug.

I create a TYPE and use it in an Array. Everything works fine. At the end I save all instances as Members of a MAP.

B4X:
Sub Process_Globals
    Type SpurenTyp(Name As String, Datei As String, Pan As Short,Volume As Short, Size As Int, Hertz As Int, Mono As Int, MaxPeak As Int  )
...



Sub Globals
    Dim SpurenDaten() As SpurenTyp
...

Sub BuildIt
    For Each Datei As String In ResultListe
        Dim locSpur As SpurenTyp=CreateSpurenTyp(BAS.SubStr(Datei,0,-4),Datei)
        SpurenDaten(Nr)=locSpur
    Next
End Sub


Public Sub CreateSpurenTyp (Name As String, Datei As String) As SpurenTyp
    Dim t1 As SpurenTyp
    t1.Initialize
    t1.Name = Name
    t1.Datei = Datei
    t1.Pan =0
    t1.Volume = 250
    t1.Size = 0
    t1.Hertz = 0
    t1.Mono = 1
    t1.MaxPeak=0
    Return t1
End Sub


Sub SaveSongMap
    For i=0 To 9
        SongProp.put("Spur" & i , SpurenDaten(i))
    Next
    File.WriteMap(File.DirRootExternal, "test.dat",SongProp)
End Sub


Sub LoadSongMap
    SongProp= File.ReadMap(File.DirRootExternal, "test.dat")
    Dim locArray(10) As SpurenTyp

    For i=0 To 9
            Log("*****reading array=" & i  & " " & SongProp.Get("Spur" & i))

        Dim locSpur As SpurenTyp=SongProp.Get("Spur" & i)
        locArray(i)=locSpur  '<---------------- App crashes here
    Next
End Sub

The file looks like this:
...
Info=no info
Spur0=[Datei\=ALTO 1.wav, Name\=ALTO 1, IsInitialized\=true\n, MaxPeak\=0, Mono\=1, Hertz\=48000\n, Pan\=0, Size\=10560414, Volume\=250\n]
HerstellerName=no name
SongName=IceCastle48

...

And the app crashes in the following start of the app, when loading the data. But not in the line where the map-datas are asigned to locSpur, but when I try to copy the locSpur into the array.

This is the error message:
*****reading array=0 [Datei=ALTO 1.wav, Name=ALTO 1, IsInitialized=true
, MaxPeak=0, Mono=1, Hertz=48000
, Pan=0, Size=10560414, Volume=250
]
zweite_loadsongmap (java line: 2010)
java.lang.ClassCastException: java.lang.String cannot be cast to midimaster.multitrack.zweite$_spurentyp
at midimaster.multitrack.zweite._loadsongmap(zweite.java:2010)
at midimaster.multitrack.zweite._readyesterday(zweite.java:2550)
at midimaster.multitrack.zweite._scanwavefiles(zweite.java:2812)
at midimaster.multitrack.zweite$ResumableSub_CheckeNeuenSong.resume(zweite.java:912)
at anywheresoftware.b4a.BA.checkAndRunWaitForEvent(BA.java:267)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:207)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:193)
at anywheresoftware.b4a.keywords.Common$14.run(Common.java:1760)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5598)
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:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)

When I try this, the app also survifes the first asignment, but crashes in the last line:
B4X:
        For i=0 To locAnzahlSpuren-1
            Log("lese array " & i  & " " & SongProp.Get("Spur" & i))
            Dim locSpur As SpurenTyp=CreateSpurenTyp("","")
            locArray(i)=locSpur
            locSpur=SongProp.Get("Spur" & i)
            locArray(i)=locSpur
....
What do I do wrong?
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
File.WriteMap
File. WriteMap (Dir As String, FileName As String, Map As Map)
Creates a new file and writes the given map. Each key value pair is written as a single line.
All values are converted to strings.

So. Using writeMap is the WRONG solution when using Custom Types.

Use B4XSerializator to read/write the Data.

B4X:
    Dim daten As Map
    daten.Initialize
    For i=0 To 9
        daten.put("Spur" & i , SpurenDaten(i))
    Next
    ' Schreiben
    Dim b4xser As B4XSerializator
    File.WriteBytes(path,filename,b4xser.ConvertObjectToBytes(daten))
   
    ' Laden
    Dim b4xser As B4XSerializator
    Dim datengelesen As Map = b4xser.ConvertBytesToObject(File.ReadBytes(path,filename))

If the data are too big then you should use the Async methods of B4XSerializator

Or use RandomAccessFile.WriteB4XObject to write.
and ReadB4XObject to read.

Or use KeyValueStore to store the map of customtypes. This is the easierst solution.
 
Last edited:
Upvote 0

Midimaster

Active Member
Licensed User
Ah thank you I will have a look on it.

But this does not explain what happened! As long a I use the local variable as TYPE, the data will be accepted an will be correct. When I use a Array of TYPES the app crashes. Even in the combination of local TYPE and Array, the datas are valid in the local variable and then when copying this variale to the array this step crashes.
If once accepted the data should be valid also in further steps, or?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
This is a mistake:
B4X:
Dim locSpur As SpurenTyp=CreateSpurenTyp("","")
            locArray(i)=locSpur
This is code smell #1:
https://www.b4x.com/android/forum/threads/b4x-code-smells-common-mistakes-and-other-tips.116651/#content

@DonManfred answer is accurate. The map returned from File.ReadMap will hold string values.
It is possible that the error is not thrown where you expect it to be thrown in debug mode. The debugger can be more lenient in some cases. You will not be able to access the type fields.
 
Last edited:
Upvote 0

Midimaster

Active Member
Licensed User
Now I do not understand anything....

This is both not allowed? How can this be a mistake?
B4X:
Sub Global
Dim Instance(10) as MyType
ChangeA(0)
'or
Instance(0)=ChangeB()

Sub ChangeA(Nr as INT)
    dim b as MyType
    b.name="peter"
    b.value=...
    Instance(Nr)=b
End Sub

Sub ChangeB() as MyType
    dim b as MyType
    b.name="peter"
    b.value=...
    return b
End Sub
 
Upvote 0

Midimaster

Active Member
Licensed User
I now decided not to use the Serializator, but to continue with the easy File.WriteMap() and File.WriteMap() functions, because I need the file for reading with an editor outside of B4A.

To clarify I have some last questions:

Is it correct, that the MAPs are able to handle User-defined types and arrays without problems?

Is it correct, that only the saving/loading to a file system brings problems?

So I only need to write special subs for decode/encode datas for WriteMap and ReadMap

something like this:
B4X:
Sub ConvertStringToArray(Text As String) As Int()
    Dim a() As String  = Regex.Split(",", Text)
    Dim b(a.Length) As Int
    For I=0 To a.Length-1
        b(I)=a(I)
    Next
    Return b
End Sub
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Is it correct, that the MAPs are able to handle User-defined types and arrays without problems?
Yes.

Is it correct, that only the saving/loading to a file system brings problems?
Question is not accurate enough. There are many ways to "save" a map. As explained many times now, File.ReadMap will return a map with strings.
 
Upvote 0
Top