Android Question Save ListView data before rotating device [solved]

Didier9

Well-Known Member
Licensed User
Longtime User
I have a logging app that saves data to a listview until the user saves it to a file.
But when the device is rotated, the ListView is cleared.
I could save the data in parallel to a list created in Starter but that would use twice the RAM. Since I want to be able to log as much data as memory allows, that is not the preferred way.
Ideally, I would like to be able to append new data to a file as it is received and prune the listview from old data but I have not found how to do that (append to a file) on B4A.

Alternately, if I could detect that the device is being rotated BEFORE the listview is cleared, I could save the data to a list in the Starter module and restore the listview content in Activity_Resume (and then clear the list to recover RAM).

At the moment, I simply freeze the orientation when the app starts, which is acceptable but not preferred.
 

emexes

Expert
Licensed User
I have not found how to do that (append to a file) on B4A.
Not sure if I am misunderstanding something here, but perhaps try:
upload_2019-10-20_9-12-25.png
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
Unless there are 10+ million items in the list then you shouldn't be concerned about it.

I did find a snippet of code returning the available RAM and the amount was in the hundreds of MB so that would be plenty. At the time of posting, I was not sure how much RAM was actually available and this is a data logger that could be running for days or longer with a minimum of 4MB/day, potentially much more. Also I do not know the overhead that using a list entails (i.e. if I have a list with 10,000 records and each is 40 bytes, that's 400,000 bytes of data but how much RAM will the list actually use?)
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
A list of 10k records where each item is about 40 bytes will take a bit more than 400kb. A medium size bitmap can take 10 times more.
A second list with the same items will take much less as the items are not really copied.

I did find a snippet of code returning the available RAM and the amount was in the hundreds of MB
Unlikely to be related to the list of items.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I'm sorry I misread the statement about the RAM. I thought that you meant that the app used hundreds of MB.

Bottom line is that you should choose the simplest implementation possible and only if you encounter a performance issue then optimize it. Otherwise you are just making things more complicated than they should be without any benefits. This is explained in the performance video tutorial.

https://www.b4x.com/etp.html?vimeography_gallery=1&vimeography_video=256924581
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
The function I am using is claimed to return available RAM:
i = (( r.RunMethod( "maxMemory" ) - r.RunMethod( "totalMemory" ))/( 1024*1024 ))
not the size of the list.
I use this to prompt the user to save the data if the available RAM drops below some value.
On the device I am using for testing, it returns 188MB or so when logging starts, and the number slowly goes down as log data is captured. I have not (yet) tried to correlate the amount of data captured and the amount of RAM available because I assume many other things can affect the amount of RAM available.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
Bottom line is that you should choose the simplest implementation possible and only if you encounter a performance issue then optimize it. Otherwise you are just making things more complicated than they should be without any benefits. This is explained in the performance video tutorial.

https://www.b4x.com/etp.html?vimeography_gallery=1&vimeography_video=256924581

In general I fully agree, particularly when it comes to speed. I have been quite surprised how fast some code I wrote was even though it was optimized for clarity, not speed.
However, this is an app that can potentially use a lot of RAM (by design because it is its intended application) and where users are likely to use the cheapest tablets available (my primary user has $27 RCA tablets that he wants to use, I believe these may have 500kB or 1MB max of RAM) so I know RAM will be tight so I do not want to start off with something that will use at least twice as much as actually needed, just to support rotation. At the moment, I freeze the orientation when the app starts and that is very effective and an acceptable trade-off (you can still run the app landscape or portrait). The conversation devolved around the more general issue of RAM use and then things are not so clear cut.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
A second list with the same items will take much less as the items are not really copied.
Of course, the data is not copied, it is just re-referenced...
Thank you.
The more I learn about it, the more I like Java...
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
This, from one of my own posts...
[...] when you add something to a list, you do not actually copy it to the list, you create a reference to it and add the reference to the list (think pointers if you are familiar with C).
 
Upvote 0

emexes

Expert
Licensed User
The conversation devolved
Yeah, I got a bit confused about the relationship between the ListView and the file. Is the ListView intended to just display the most recent n (100? 1000?) datalog entries, or the entire history ie the entire file?

I feel like you should be buffering the readings into a regular memory-based list, and then flushing that list to file as required, eg when memory is low, or when the ListView is to be recreated, or after some timeout period eg once a minute.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
Well, this started as just a simple extension on the UsbSerial library example for a friend who want to use cheap tablets to log data on a bunch of timing-related devices.
This is potentially time consuming, data consuming and hardware consuming...
He wants to see the data and save it to a file if he decides to. He is not very computer literate so I had to compile his wish-list into something I could code.
My first approach was to save the data in a ListView for display and storage until such time that he decides to save it.
The problem with the listview is that it goes away when you rotate the device so I started looking for workarounds.
And here we are :)
Yes, I thought about saving to a list and only display the most recent data in a listview but that is more coding and as Erel pointed out, it will not save RAM.
So at the moment, I will keep what I have (freeze orientation and use the ListView for storage AND display until such time the data is saved to a file) unless/until my friend makes a compelling case that he should be able to rotate the device while it is running. In that case, I will mirror the data in a list and restore the listview from the list when the devide is rotated. That's not much code.
The reason for wanting to rotate is that the actual length of data that is recorded (the individual records) do not have necessarily fixed length so you could start in portrait and find out some data is outside the display area and would like to see that without losing the data already in the ListView.
But life is tough and sometimes you have to make hard choices and it is one of those times :)
 
Upvote 0

emexes

Expert
Licensed User
A technique that can be useful for long log periods is to write the data into files with names based on date/time, eg, daily files like data-20191020.csv or hourly files like data-20191020-1300.csv. This makes it easier to manage disk space issues, eg to compress (eg Zip) or reduce/summarize older data without affecting the current data, or to delete old data if disk space is getting low (assuming that losing old data is preferable to losing recent data).
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
A technique that can be useful for long log periods is to write the data into files with names based on date/time, eg, daily files like data-20191020.csv or hourly files like data-20191020-1300.csv. This makes it easier to manage disk space issues, eg to compress (eg Zip) or reduce/summarize older data without affecting the current data, or to delete old data if disk space is getting low (assuming that losing old data is preferable to losing recent data).
That is what I do. I use the time the file is created as the filename. I also put the time recording starts as the first item in the list, so you know when recording started and when it ended with a minimum of fuss.
When the user saves the data, I clear the ListView so the next file will start where the previous one ended.
I may also add time stamps to each record as a user selectable option.
 
Upvote 0

emexes

Expert
Licensed User
Well, this started as ... And here we are :) ... But life is tough and sometimes you have to make hard choices and it is one of those times :)
That post made me laugh, and it deserves more than just a like click. Brought back memories of past rabbit holes I've gone down, only to emerge later in some entirely different - and sometimes only very-loosely related - area of programming.

Plus I can see you've got things under control, so I'll leave you in peace rather than distract you from the task at hand.

:)
 
Upvote 0
Top