Jump to content
Fabian1648

[Android] How to put data from a dataset into a listbox?

Recommended Posts

Hi,

 

In an Android app, I'm retrieving some data (3 columns) from a dataset and need to display it in a Listbox with 3 fields in each line.

 

If I use the following procedure in a loop, adding one line after another, it works for about ten lines, but when it comes to displaying a hundred lines, the process is too slow.

 

...
 ListBox1.BeginUpdate;
try
 for i:=0 ...
  ...
  AddListBoxItem(Listbox1,value1[i],value2[i],value3[i]);
  ...
 end;

finally
 ListBox1.EndUpdate;
end;


//*********************


procedure TForm1.AddListBoxItem(myListBox:TListBox;Definition, Qty1, Qty2:string);
begin
...

  ListBoxItem:= TListBoxItem.Create(myListBox);
  ListBoxItem.Parent:= myListBox;

  ListBoxItem.ApplyStyleLookup;

  ListBoxItem.StylesData['Reference.text']:=Definition;
  ListBoxItem.StylesData['Qty1.text']:=Qty1;
  ListBoxItem.StylesData['Qty2.text']:=Qty2;
...
end;

 

 

It's much faster if the data extracted from the dataset are placed in a Stringlist and I transmit the data to the listbox in a single operation using "myListBox:=myStringList".

 

In this case, the values are only in the 1st field of the listbox.

 

How can I perform the same kind of operation to put the data in ListBox fields 2 and 3?

Share this post


Link to post

Why don't you use a TListView with dynamic appearance and Livebindings ?   

Share this post


Link to post

Hi,

 

1. If I don't use Livebindings, it's because I can't use Livebindings (the source is a dataset > I extract some columns of this dataset to display these in a visual component)

 

2. This speed problem occurs with all visual components (Combobox, Listbox, etc...)

 

3. I've already solved a similar problem with combobox: Dataset > Stringlist > Listbox.assign(Stringlist). For 1000 lines, the delay goes from more than 30 sec to 500 millisec!. In the case of the Listbox, I don't have just one dimension, but two: not just  lines, but lines made up of 3 distinct fields.

Share this post


Link to post

The way you're currently doing this is creating a new TListBoxItem for each row of data, and then applying the styles and setting the data for each. This is a relatively expensive operation, particularly if you're doing it hundreds of times in a loop.

Instead, consider batching your data updates. One common way to do this is to create a list of objects (each containing the three pieces of data for each row), and then update the ListBox with this list all at once.

To do this, you could define a simple class to hold your data:
 

type
  TListBoxData = class
    Definition: string;
    Qty1: string;
    Qty2: string;
  end;

Then, you could create a list of these objects and fill it with your data:
 

var
  DataList: TObjectList<TListBoxData>;
  i: Integer;
  Data: TListBoxData;
begin
  DataList := TObjectList<TListBoxData>.Create;
  try
    for i := 0 to ... do
    begin
      Data := TListBoxData.Create;
      Data.Definition := value1[i];
      Data.Qty1 := value2[i];
      Data.Qty2 := value3[i];
      DataList.Add(Data);
    end;
    
    UpdateListBox(DataList);
  finally
    DataList.Free;
  end;
end;

Then, in your UpdateListBox procedure, you could loop through this list of data objects and add them to the ListBox:
 

procedure TForm1.UpdateListBox(DataList: TObjectList<TListBoxData>);
var
  i: Integer;
  ListBoxItem: TListBoxItem;
begin
  ListBox1.BeginUpdate;
  try
    for i := 0 to DataList.Count - 1 do
    begin
      ListBoxItem := TListBoxItem.Create(ListBox1);
      ListBoxItem.Parent := ListBox1;
      
      ListBoxItem.StylesData['Reference.text'] := DataList[i].Definition;
      ListBoxItem.StylesData['Qty1.text'] := DataList[i].Qty1;
      ListBoxItem.StylesData['Qty2.text'] := DataList[i].Qty2;
      
      ListBoxItem.ApplyStyleLookup;
    end;
  finally
    ListBox1.EndUpdate;
  end;
end;

This will allow you to create and set up all your TListBoxItem instances in one batch, which should significantly improve performance.

If you still experience performance issues, you may want to look into using a virtualized list control that only creates and renders items as they're needed. This can significantly improve performance when dealing with large amounts of data.

Please note that this code was written in Delphi since you posted Delphi-like code, but you mentioned Android in the beginning. If you're using Kotlin or Java for Android development, the approach would be different

  • Like 1

Share this post


Link to post

Hi,

Thank for your answer Martifan.

 

The code is actually written in Delphi.

 

I tested your solution and I get exactly the same time to perform the operation as my best solution (6 sec for 1 000 items!).

 

The following operation takes far too long because  it adds one ListBoxItem after another

    for i := 0 to DataList.Count - 1 do
    begin

      ...
      
      ListBoxItem.StylesData['Reference.text'] := DataList[i].Definition;
      ListBoxItem.StylesData['Qty1.text'] := DataList[i].Qty1;
      ListBoxItem.StylesData['Qty2.text'] := DataList[i].Qty2;

If I use a "Listbox.assign(ListObject)", the delay for 1 000 items goes from more than 6 sec to 500 millisec because all ListBoxItem are added in one shot. The problem is that only the field Reference of ListBoxItems is completed... 

 

The question is .... Is it possible to fill in the other fields of a ListBoxItem using an assign function?

Edited by Fabian1648

Share this post


Link to post

The slow speed is likely due to frequent user interface (UI) updates during the loop. To overcome this, you can use the ListBox.Items.BeginUpdate and ListBox.Items.EndUpdate methods to prevent the ListBox from updating the UI for each addition, thereby significantly speeding up the process.

Here is an example of how to use it:

ListBox.Items.BeginUpdate;
try
  for i := 0 to DataList.Count - 1 do
  begin
    ...
      
    ListBoxItem.StylesData['Reference.text'] := DataList[i].Definition;
    ListBoxItem.StylesData['Qty1.text'] := DataList[i].Qty1;
    ListBoxItem.StylesData['Qty2.text'] := DataList[i].Qty2;
    ...
  end;
finally
  ListBox.Items.EndUpdate;
end;

This BeginUpdate and EndUpdate pair can significantly increase the speed of your ListBox updates, as the control does not need to refresh the UI with each added item. Instead, it waits until all updates are complete and refreshes the UI just once, thus saving time.

Share this post


Link to post

I already use ListBox.Items.BeginUpdate and ListBox.Items.EndUpdate. This reduced the display of 1,000 ListBox items from 30 seconds to 6 seconds.

 

As already written, what's wrong is adding one listboxitem after another in a loop. This is equivalent to an action for each item.

 

If you assign a Listobject to the Listbox, it's a single action.

 

I've tested the assignment method; it's immediate, but I can only do it for the main ListBox field.

 

My question is whether it's possible to make an assignment that updates the other two ListBox fields by making a single assignment for the ListBox, or an assignment for each of the 3 fields, which would make it possible to do 3 actions at worst instead of 1000.

 

Edited by Fabian1648

Share this post


Link to post
On 7/25/2023 at 10:01 AM, Fabian1648 said:

Hi,

 

1. If I don't use Livebindings, it's because I can't use Livebindings (the source is a dataset > I extract some columns of this dataset to display these in a visual component)

 

2. This speed problem occurs with all visual components (Combobox, Listbox, etc...)

 

If speed is your issue here, then maybe because you try to use too many items in the ListBox.

Perhaps, better switch to TListView then ?

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×