Android Question Saving custom type with bitmaps to Random Access File

Jose Miranda

Member
Licensed User
Longtime User
I trying to write a custom type to a file using RandomAccessFile.

My type is defined as:
B4X:
Type opt (stars As Bitmap, nebula As Bitmap, magnitude As Int, star As Boolean, obj As String, fl As String, EPFl As String, epAFOV As String, notes As String)

Im saving the file using this code:
B4X:
option.stars=Stars.Bitmap
    option.nebula=Nebula.Bitmap
    option.obj=obj.Text
    option.magnitude=magnitude.Value
    option.star=star.Checked
    option.fl=FL.Text
    option.EPFl=EPFl.Text
    option.epAFOV=epAFOV.Text
    option.notes=Notes.text
   
    raf.Initialize(Path, filename, False)
    raf.WriteObject(option, True, raf.CurrentPosition)
    raf.Close

And reading it with:
B4X:
Dim raf As RandomAccessFile
    Dim s,n As Bitmap
    Dim srect, nrect As Rect
   
    raf.Initialize(File.DirRootExternal & "/Astropad", "drawing.dat", False)
    option=raf.ReadObject(raf.CurrentPosition)
    srect.Initialize(0,0,option.stars.Width,option.stars.height)
    nrect.Initialize(0,0,option.nebula.Width,option.nebula.height)
    Stars.DrawBitmap(s,srect,srect)
    Nebula.DrawBitmap(n,nrect,nrect)
    magnitude.Value=raf.ReadObject(raf.CurrentPosition)
    star.checked=raf.ReadObject(raf.CurrentPosition)
    obj.text=raf.ReadObject(raf.CurrentPosition)
    FL.text=raf.ReadObject(raf.CurrentPosition)
    EPFl.text=raf.ReadObject(raf.CurrentPosition)
    epAFOV.text=raf.ReadObject(raf.CurrentPosition)
    Notes.text=raf.ReadObject(raf.CurrentPosition)

When I debug the writing sub i can see stars=Bitmap and nebula=Bitmap in the Global variables panel. When I debug the reading sub I see stars=null and nebula=null and the code fails after the ReadObject line.

I dont understand what Im doing wrong... can you please help?
 

Jose Miranda

Member
Licensed User
Longtime User
See the documentation about raf.WriteObject / ReadObject. There are types that cannot be saved with these methods. You should use KeyValueStore class (see the Similar Threads above). It will allow you to read and write bitmaps.

OK I ditched the custom type since the code is much simpler using this class (i can access any object written to the file without knowing its position, that's awesome!). The only problem I found with the class is that it is returning 0 and 1 for booleans and java is complaining that it cannot parse 1 as a Boolean...

It seems that booleans inserted in the database as a string and thus retrieved as a string. So since there is no way of telling if it was a string, integer or boolean it just returns the contents...? Im not sure...

So I added a new sub that is basically a copy of GetSimple but returns a boolean. I'm not sure if this is OK or not but it worked for me.

B4X:
'Returns a Boolean value. See PutSimple.
Public Sub GetBoolean(Key As String) As Boolean
    Dim c As Cursor = getCursor(Key)
    If c.RowCount = 0 Then Return ""
    c.Position = 0
    Dim res As String = c.GetString2(0)
   
    c.Close
    If res=1 Then
        Return True
    Else
        Return False
    End If
End Sub

What do you think?
 
Upvote 0

Jose Miranda

Member
Licensed User
Longtime User
You can use PutObject / GetObject. It should work fine.

Got an error using both GetObject and PutObject. Tried using PutSimple and got the error below.

B4X:
keyvaluestore_getobjectinternal (B4A line: 171)
Dim buffer() As Byte = c.GetBlob2(0)
android.database.sqlite.SQLiteException: unknown error (code 0): INTEGER data in nativeGetBlob
    at android.database.CursorWindow.nativeGetBlob(Native Method)
    at android.database.CursorWindow.getBlob(CursorWindow.java:403)
    at android.database.AbstractWindowedCursor.getBlob(AbstractWindowedCursor.java:45)
    at anywheresoftware.b4a.sql.SQL$CursorWrapper.GetBlob2(SQL.java:409)
    at MirandaApps.AstroPad.keyvaluestore._getobjectinternal(keyvaluestore.java:386)
    at MirandaApps.AstroPad.keyvaluestore._getobject(keyvaluestore.java:349)
    at MirandaApps.AstroPad.main._retrievedata(main.java:1168)
    at MirandaApps.AstroPad.main._activity_resume(main.java:501)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
    at MirandaApps.AstroPad.main.afterFirstLayout(main.java:95)
    at MirandaApps.AstroPad.main.access$100(main.java:16)
    at MirandaApps.AstroPad.main$WaitForLayout.run(main.java:74)
    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:4898)
    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:1008)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:775)
    at dalvik.system.NativeStart.main(Native Method)
android.database.sqlite.SQLiteException: unknown error (code 0): INTEGER data in nativeGetBlob
 
Upvote 0

Jose Miranda

Member
Licensed User
Longtime User
The error message you got happens because you added the item with PutSimple and then tried to fetch it with GetObject.

Thats because I tried using PutObject to put the boolean but it gave me an error... anyway, I got away with my PutBoolean function
 
Upvote 0
Top