Android Question Save CustomListView to a file?

Branko Milosevic

Active Member
Licensed User
I have a CustomListView I need to save to read from a file on activity resume and save back to the file on activity pause.
Is it possible to use File.ReadList and File.WriteList without going through looping CustomViewList to populate an intermediate list with item values of interest?
What I am looking for is to avoid looping through the list.

Thanks,
 

Branko Milosevic

Active Member
Licensed User
You don't save UI elements. You save data.

How are you creating the CLV items?

Items are created in a loop. I am guessing I would need to use value parameter and pass it an object that contains all my data.

CLV items are three labels and two panels created in Designer.
Three labels and two panels.

Label1 data is label.text="some text"
Label2 data is label2.text=string of a number
Label3 data is label3.text=string of a number
Panel1 data is panel1.width=number contained in Label2 (creates a colored thick line as visual representation of the number)
Panel2 data is panel2.width=number contained in Label3 (creates a colored thick line as visual representation of the number)

I am guessing I will have to loop trough CLV anyways because all of these are UI elements.

So if I create an object that contains all my data and pass that object to the value parameter would this object be handled by File.writelist/readlist?
That would still help when looping to recreate Items because data is handy at the same index location. Better than maintaining a separate list and risk indexing errors.

thanks,
 
Last edited:
Upvote 0

Branko Milosevic

Active Member
Licensed User
Don't use File.WriteList / ReadList.

Use RandomAccessFile.WriteB4XObject. It will allow you to write a List that holds custom types.
B4X:
Type ClvValues (member1 as in,member2 as in,member3 as in)
Dim Members as ClvValues

For index=0 to 9                           'loading Clv
         Member.member1=index
         Member.member2=index
         Member.member3=index

          MyClv.Add(blahblahblah.,...,...blahblah, Members)
Next

for index=0 to 9                                        'writing to raf
         Members=MyClv.GetValue(index)
         raf.WriteB4XObject(Members,index)
Next


For index=1 to 9                                     'reading from raf and recreating Clv
         Members=raf.readB4XObject(index)
         MyClv.Add(blahblahblah.,...,...blahblah, Members)

Next

This concept doesn't work for some reason on the readB4XObject part.
I suspect that index of the raf isn't the same as of the Clv and it's moving byte by byte.

Do I need to create a new list first and populate it with Members and then write the list in one line?
 
Upvote 0

Branko Milosevic

Active Member
Licensed User
B4X:
Type ClvValues (member1 as in,member2 as in,member3 as in)
Dim Members as ClvValues

For index=0 to 9                           'loading Clv
         Member.member1=index
         Member.member2=index
         Member.member3=index

          MyClv.Add(blahblahblah.,...,...blahblah, Members)
Next

for index=0 to 9                                        'writing to raf
         Members=MyClv.GetValue(index)
         raf.WriteB4XObject(Members,index)
Next


For index=1 to 9                                     'reading from raf and recreating Clv
         Members=raf.readB4XObject(index)
         MyClv.Add(blahblahblah.,...,...blahblah, Members)

Next

This concept doesn't work for some reason on the readB4XObject part.
I suspect that index of the raf isn't the same as of the Clv and it's moving byte by byte.

Do I need to create a new list first and populate it with Members and then write the list in one line?
OK, I do need a list e.g "MembersList" to hold my custom type Members and update this list whenever an update is done on the Clv.

Then
B4X:
raf.writeB4XObject(MembersList,0)    'writes entire list at the beginning of the file.

MembersList=raf.readB4XObject(0)     'reads entire list from the beginning of the file

I am happy now :)
 
Upvote 0

Branko Milosevic

Active Member
Licensed User
Don't use File.WriteList / ReadList.

Use RandomAccessFile.WriteB4XObject. It will allow you to write a List that holds custom types.
I still have trouble with this.

I made a custom type object which I hold in CustomListView value.
I also have a LIST to hold same object for the purpose of saving to a file. I maintain relationship between the LIST items and the CustomListView list items on any change.

My problem is this:
The custom type object has to be an array of objects. Which is fine but the problem is it also needs to be synchronized with the LIST or I end up with a warning: same object added to the list multiple times, when adding new items after the two lists are re-sized.

removeAT or insertAT unfortunately are not available for arrays of objects which is where my problem is.

Huh, have to turn AC up a notch....
 
Upvote 0

Branko Milosevic

Active Member
Licensed User
Why do you need to use two lists? Add the data you want to save as the CLV items value. Create a new list and fill it from the CLV items when you want to save.


No. It can be a regular List.

I have three numbers that I need to store in CLV Items value. From time to time I need to save them and use them after to rebuild the CLV list.
I tried with a custom type object with three members. This object will have to have an instance for every CLV Item. So it's an array of objects.
When i put same object in all Item values I got a warning that same the object is inserted multiple times which I ignored but later leaned when I change values of custom type members values of all Items got changed.



B4X:
Type CustomType (member1 as int, member2 as int, member3 as in)
dim members as CustomType

For I = 1 to 10
members.member1=i+1
members.member2=i+2
members.member3=i+3

ClvAdd(...............,members)

next
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I got a warning that same the object is inserted multiple times which I ignored
This is a mistake.

This object will have to have an instance for every CLV Item. So it's an array of objects.
This is also not correct. You can use a List instead of an array. Lists are more powerful and are easier to work with.

See the common mistake explained here: https://www.b4x.com/android/forum/threads/variables-objects-in-basic4android.8385/#content
 
Upvote 0

Branko Milosevic

Active Member
Licensed User
This is a mistake.


This is also not correct. You can use a List instead of an array. Lists are more powerful and are easier to work with.

See the common mistake explained here: https://www.b4x.com/android/forum/threads/variables-objects-in-basic4android.8385/#content
Maybe I am not explaining myself well. The goal is to have three values unique to each CLV Item
here is a code using a custom type and Log of entire CLV when populated. This didn't work as all Clv Items have the same Custom Type object and only the last value is stored in all Clv Items.


B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
  
    Private Clv As CustomListView
    Type CustomType (member1 As Int, member2 As Int, member3 As Int)
    Dim members As CustomType
  
    Private Button1 As Button
    Private Label1 As Label
End Sub

Sub Activity_Create(FirstTime As Boolean)
  
    Activity.LoadLayout("CLV")
    Clv.Clear
      
    For i = 1 To 10
        members.member1=i
        members.member2=i
        members.member3=i

        Clv.Add(CreateListItem("this is Item"&i),70dip,members)
    Next
          Log(Clv)
  
    End Sub

here is the Log(Clv)
B4X:
[sv=(MyScrollView): Left=0, Top=0, Width=320, Height=330, callback=class b4a.example.main,
, items=(ArrayList) [[IsInitialized=false, member1=10, member2=10
, member3=10], [IsInitialized=false, member1=10, member2=10
, member3=10], [IsInitialized=false, member1=10, member2=10
, member3=10], [IsInitialized=false, member1=10, member2=10
, member3=10], [IsInitialized=false, member1=10, member2=10
, member3=10], [IsInitialized=false, member1=10, member2=10
, member3=10], [IsInitialized=false, member1=10, member2=10
, member3=10], [IsInitialized=false, member1=10, member2=10
, member3=10], [IsInitialized=false, member1=10, member2=10
, member3=10], [IsInitialized=false, member1=10, member2=10
, member3=10]], eventname=clv, dividerheight=2.0
, defaulttextsize=14, defaulttextcolor=-4276546, defaulttextbackgroundcolor=-16777216
, animationduration=300]
** Activity (main) Resume **

Now I changed the Custom Type to Custom Type array. This provided the unique values for each Clv Item but it's an array which is difficult to sync with Items when Clv is re-indexed during removal or insertion of Items.

B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
  
    Private Clv As CustomListView
    Type CustomType (member1 As Int, member2 As Int, member3 As Int)
    Dim members(100) As CustomType
  
    Private Button1 As Button
    Private Label1 As Label
End Sub

Sub Activity_Create(FirstTime As Boolean)
  
    Activity.LoadLayout("CLV")
    Clv.Clear
      
    For i = 1 To 10
        members(i).member1=i
        members(i).member2=i
        members(i).member3=i

        Clv.Add(CreateListItem("this is Item"&i),70dip,members(i))
    Next
          Log(Clv)
  
    End Sub


And here is the Log(Clv) now with unique values

B4X:
[sv=(MyScrollView): Left=0, Top=0, Width=320, Height=330, callback=class b4a.example.main,
, items=(ArrayList) [[IsInitialized=false, member1=1, member2=1
, member3=1], [IsInitialized=false, member1=2, member2=2
, member3=2], [IsInitialized=false, member1=3, member2=3
, member3=3], [IsInitialized=false, member1=4, member2=4
, member3=4], [IsInitialized=false, member1=5, member2=5
, member3=5], [IsInitialized=false, member1=6, member2=6
, member3=6], [IsInitialized=false, member1=7, member2=7
, member3=7], [IsInitialized=false, member1=8, member2=8
, member3=8], [IsInitialized=false, member1=9, member2=9
, member3=9], [IsInitialized=false, member1=10, member2=10
, member3=10]], eventname=clv, dividerheight=2.0
, defaulttextsize=14, defaulttextcolor=-4276546, defaulttextbackgroundcolor=-16777216
, animationduration=300]

You are saying to use List. I would if there is a multidimensional list available?
 
Last edited:
Upvote 0

Branko Milosevic

Active Member
Licensed User
Got it now Erel. I thought CustomType has to be declared in Globals. My mistake, it's the Type that has to be declared in Globals not the variable itself which I am now gonna Dim as CustomType to create a new instance of it just before its values need to be changed.
I have never used Custom Type for a variable with such a short scope.
This is great thanks,
 
Upvote 0

Branko Milosevic

Active Member
Licensed User
Now if CLV.value is a List of Custom Types, removal of a CLV Item isn't going to remove a corresponding index List item so the list has to be updated with the same remove/replace/add operation whenever it is done on the CLV.
Question 1. Can I avoid the List and store Custom Types (different instances of course) directly in CLV? I know I could but the interest is in relation to the question 2.
Question 2. Can CLV be saved with raf.Write(Read)B4XObject?
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
removal of a CLV Item isn't going to remove a corresponding index List item
It´s up to you to remove the item from your global list when you remove a clv-item.
Get the CustomType from the CLV.
Check the index from the CustomType inside your list with
B4X:
mylist.IndexOf(MyCustomItem)
to get the right itemindex in your List. Then you can remove this item from your List.
 
Upvote 0

Branko Milosevic

Active Member
Licensed User
It´s up to you to remove the item from your global list when you remove a clv-item.
Get the CustomType from the CLV.
Check the index from the CustomType inside your list with
B4X:
mylist.IndexOf(MyCustomItem)
to get the right itemindex in your List. Then you can remove this item from your List.
Thanks I can do that and in case of resizing to do simultaneous change on both. It would still simplify if I can have CustomTypes directly in the CLV value and be able to save CLV to the RandomAccessFile.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Please make sure to read my answers. Everything was answered in this thread more than once.

For the last time, you don't need to have another list. Just add the values to the CLV items and create a new list when you want to save it:
B4X:
Dim NewList As List
NewList.Initialize
For i = 0 To CLV.GetSize - 1
 NewList.Add(CLV.GetValue(i)
Next
'save NewList to file
 
Upvote 0

Branko Milosevic

Active Member
Licensed User
See my answer in post #8. There is no reason to maintain another list. Just create the list based on the CLV items values before you write it.
OK maintenance of the list is eliminated now and customtypes are stuffed directly into the CLV item value.
Now to go step further because I have to do the Write very often I was trying to avoid this intermediate list before saving. Saving CLV directly to raf would help if possible?

I would extract item values upon reading it and recreate the CLV from it.
 
Upvote 0

Branko Milosevic

Active Member
Licensed User
Please make sure to read my answers. Everything was answered in this thread more than once.

For the last time, you don't need to have another list. Just add the values to the CLV items and create a new list when you want to save it:
B4X:
Dim NewList As List
NewList.Initialize
For i = 0 To CLV.GetSize - 1
NewList.Add(CLV.GetValue(i)
Next
'save NewList to file
Sorry you are replying too fast :) so my replay to DonMAnfred was out of sync and came after yours.
 
Upvote 0
Top