Android Question Cannot access object fields after writing/reading a map to/from a file

CoderMaan

Member
Licensed User
Longtime User
Since I think I've tried almost everything to make my program work as I think it should work, the following is mostly just a commentary and warning to help anyone else who is trying to use a map after reading it back from a file. In particular, although I can fully access the fields of an object in the map before it's written to a file, I certainly don't seem to be able to access the same fields after reading the map back from the file ... unless the objects stored in the map were no more than Strings to begin with, that is.

The attached code shows what happens when I try to access the discrete components of an object that is placed in a map---and then saved to a file---and then read back from the file. When I try to access the discrete components (of the non-string object) after successfully reading the map from the file AS WELL AS the object that was originally placed in the map, the program crashes. I suppose that is to be expected, given the wording in the library explanation of File.WriteMap, namely, "All values are converted to strings."

But if that's the way it's supposed to work, maybe the File.WriteMap explanation should at least have a warning message such as "Integrity is not maintained when non-string objects are saved to file."

In the attached program everything is fine up to and including Log (3), but the program crashes on the line with Log (4), (apparently) simply because I am trying to access a component of the object (that was successfully printed in Log (3).

Unfortunately, I guess this means that the line (in my code)
ObjZ = MapY.Get("Key1")
is not really storing an object of type ObjectType1 in ObjZ, but is instead storing a string in that object (if that's possible!)

Anyway, I've finally accepted that I'll probably have to write some routines to access the components of the object(s) that I save in the map and store to a file that I then read back. However, I cannot help but wonder what is the purpose of the File.WriteMap and File.ReadMap routines, if it is not to actually store the map as a map, and the objects in the map as objects in a map.

If someone cares to comment, or better yet, to enlighten me and show me that it is possible to fully access the objects that are found in the map that I've read back from the file, PLEASE DO so! I would love to say that I've simply overlooked something, and that this particular oddity of B4A is not really that odd at all.

Even if you can't give me an easy fix, I'm still liking B4A a lot : )

CoderMaan

PS: The code is attached, but it's also include below---along with the log entries---for anyone who does not want to actually open the file.


B4X:
#Region  Project Attributes
    #ApplicationLabel: B4A Example2
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
End Sub

Sub Globals
    Type ObjectType1 (Field1 As String, Field2 As String)
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Dim ObjX, ObjY, ObjZ As ObjectType1
    Dim Str1, Str2, Str3, Str4, Str5 As String
    Dim MapX, MapY As Map
   
        ObjX.Initialize  :  ObjY.Initialize  :  ObjZ.Initialize  :  MapX.Initialize  : MapY.Initialize
        Str1 = "1st string"  :  Str2 = "2nd string"  :  Str3 = "3rd string"  :  Str4 = ""
   
        ObjX.Field1 = Str1
        ObjX.Field2 = Str2
   
        MapX.Put("Key1", ObjX)
        MapX.Put("Key2", Str3)
   
        ObjY = MapX.Get("Key1")
        Log("(1) Partial contents of object in map before writing it to file: " & ObjY.Field1)
   
    File.WriteMap(File.DirDefaultExternal, "Tmp140811x1615.txt", MapX)
    MapY = File.ReadMap(File.DirDefaultExternal, "Tmp140811x1615.txt")
   
        Str4 = MapY.Get("Key2")
        Log("(2) Contents of String in map after reading back from file: " & Str4)
        ObjZ = MapY.Get("Key1")
        Log("(3) Object in map after reading back from file: " & ObjZ)
        Log("(4) Partial contents of object in map after reading back from file: " & ObjZ.Field1)   
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

And here are the log entries:


** Activity (main) Create, isFirst = true **


(1) Partial contents of object in map before writing it to file: 1st string


(2) Contents of String in map after reading back from file: 3rd string


(3) Object in map after reading back from file: [Field1=1st string, Field2=2nd string, IsInitialized=true


]
Error occurred on line: 46 (main)
java.lang.RuntimeException: Field: Field1 not found in: java.lang.String
at anywheresoftware.b4a.shell.Shell$FieldCache.getField(Shell.java:833)
at anywheresoftware.b4a.shell.Shell.getField(Shell.java:604)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:314)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:238)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:121)
at b4a.example.main.afterFirstLayout(main.java:98)
at b4a.example.main.access$100(main.java:16)
at b4a.example.main$WaitForLayout.run(main.java:76)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
** Activity (main) Resume **
 

Attachments

  • m140811_ForumQuestion_2.zip
    6.7 KB · Views: 112

DonManfred

Expert
Licensed User
Longtime User
Use RandomAccessFile to write (read) the Map-Object...
Using RandomAccessFile will help you using your Map with any kind of Object inside, not just strings.

B4X:
'File.WriteMap(File.DirDefaultExternal, "Tmp140811x1615.txt", MapX)
Dim ra As RandomAccessFile
ra.Initialize(File.DirDefaultExternal, "Tmp140811x1615.txt", False)
ra.WriteObject(MapX,False,0)

'MapY = File.ReadMap(File.DirDefaultExternal, "Tmp140811x1615.txt")
MapY = ra.ReadObject(0)
** Activity (main) Create, isFirst = true **
(1) Partial contents of object in map before writing it to file: 1st string
(2) Contents of String in map after reading back from file: 3rd string
(3) Object in map after reading back from file: [Field1=1st string, Field2=2nd string, IsInitialized=true]
(4) Partial contents of object in map after reading back from file: 1st string
** Activity (main) Resume **
 

Attachments

  • m140811_anwerfromforum.zip
    6.8 KB · Views: 121
Last edited:
Upvote 0
Top