slint
slint copied to clipboard
Please can you make an example which demonstrate how to scale using ListView
Hi,
I would like to know how to work best with ListView
when using slint and rust.
Here is the problem:
- I have a very large array (possibly 10K+ items)
- In order to not exhaust my system, I'll only have one attribute in that list:
int item-id
- the list will create an
ItemWidget
component for each entries, binding theitem-id
property -
ItemWidget
will have to fetch multiple information which can't be loaded and computed from the main thread:- images
- result of expensive calculation
- database lookup
I wonder how to best solve that issue with Slint? How and when will be disposed the requested resources?
Additionally, how to work best with large ModelRc
? Is it using a vector? What is the complexity if I remove an item in the middle of the array?
Please could you make an example that illustrate this problem and demonstrate the best practices to solve it?
Thank you very much, and if the problem description isn't clear, please let me know and I'll try to clarify it.
Cheers, Alex
A simple application to illustrate that problem, could be an application which displays all images within a folder in a list view.
Take a folder that is packed with a lot of images, list the directory, and display each images scaled to 128x128, one image per line.
This will involve disk I/O and image loading+scaling (expensive computation), both can't be done on the main thread.
Enjoy :-)
Suppose you're showing a list of images from the network. If the server is very slow to respond, you'd have to show a list of placeholders, until the data has arrived, right?
Later, when the data arrived, you'd update your model and call row_changed()
on the ModelNotify
(if you're implementing your own Model
).
An extreme way would be to do this entirely lazily, so issue the network request for a certain row only when row_data()
is called for it the first time. But that means that scrolling will always show a placeholder first.
So ideally we'd have an additional callback in the Model
to allow the ListView
to notify when the user scrolls and we anticipate a certain amount of rows to become visible in the near future, so that your model can pre-fetch.
I think it makes sense to have an example for this, yes. I wonder what kind of say web service to use for this that for example provides images (or thumbnails of something).
I think images on the web is overkill, loading images from disk is enough, you can add a sleep(1s) to simulate slow disk I/O.
Can reference my project:https://github.com/wuanzhuan/system_monitor. view the src/ui/events_view.slint and src\event_list.rs. the list synchronously support push_back, remove and read cursor. when has 300k+ items it is fluent to sliding the table_view
Can reference my project:https://github.com/wuanzhuan/system_monitor. view the src/ui/events_view.slint and src\event_list.rs. the list synchronously support push_back, remove and read cursor. when has 300k+ items it is fluent to sliding the table_view
Thank you, but I don't think it is the same problem. Imagine that each row costs you 4 MB of RAM, and 2s to compute. You can't have a vector of 300k rows, you'd need a lazy model instead, something like:
-
prefetch_row(row_index)
-
release_row(row_index)
Can reference my project:https://github.com/wuanzhuan/system_monitor. view the src/ui/events_view.slint and src\event_list.rs. the list synchronously support push_back, remove and read cursor. when has 300k+ items it is fluent to sliding the table_view
Thank you, but I don't think it is the same problem. Imagine that each row costs you 4 MB of RAM, and 2s to compute. You can't have a vector of 300k rows, you'd need a lazy model instead, something like:
prefetch_row(row_index)
release_row(row_index)
I don't use the vector. It is a intrusive double linked list. Each row is wrapped in Arc. So can freely push、remove and share. It don't need continuous memory for entire rows. Just optimize the index query for the list
I don't use the vector. It is a intrusive double linked list. Each row is wrapped in Arc. So can freely push、remove and share. It don't need continuous memory for entire rows. Just optimize the index query for the list
You're missing the point. Yes an intrusive linked list is an elegant solution for the container, but here the container isn't the issue. The issue is about a single row being heavy to compute and to keep in memory, and a request to have some support for lazy model in order to just compute the rows which are displayed and release the one which aren't anymore.
I do a test. Only the visible row will call Model 's row_data. So you can load the row's resource when calling the row_data
I do a test. Only the visible row will call Model 's row_data. So you can load the row's resource when calling the row_data
But then how do you know which rows aren't displayed anymore and can be released?
I do a test. Only the visible row will call Model 's row_data. So you can load the row's resource when calling the row_data
But then how do you know which rows aren't displayed anymore and can be released?
Assume the current visible rows's index is 0..10. the totle rows's len is 10001. the 11..10000 can be release. but you need to consider preload according to your situation.
I do a test. Only the visible row will call Model 's row_data. So you can load the row's resource when calling the row_data
But then how do you know which rows aren't displayed anymore and can be released?
Assume the current visible rows's index is 0..10. the totle rows's len is 10001. the 11..10000 can be release. but you need to consider preload according to your situation.
Exactly that's why it'd be better to have a LazyModel with prefetch/release support.
I do a test. Only the visible row will call Model 's row_data. So you can load the row's resource when calling the row_data
But then how do you know which rows aren't displayed anymore and can be released?
Assume the current visible rows's index is 0..10. the totle rows's len is 10001. the 11..10000 can be release. but you need to consider preload according to your situation.
Exactly that's why it'd be better to have a LazyModel with prefetch/release support.
I don't think this belongs to the category of UI. Now the Model only hold the visible rows. it is a lazy yet.
I've mitigated it using a bunch of LRU caches and:
fn row_data(&self, row: usize) -> Option<Self::Data> {
let result = self.fetch_row_data(row);
if TITAN.library_results_enable_prefetch {
for i in 0..TITAN.library_results_prefetch_size {
if row >= i {
let _ = self.fetch_row_data(row - i);
}
let _ = self.fetch_row_data(row + i);
}
}
result
}
I'm not sure if I'm entirely happy with that solution, I believe that it'd be better if managed by the widget.