在运行时创建大量控件以最小化 firemonkey 中的加载时间的最佳方法是什么?

What is the best way to create a lot of controls at runtime to minimize the load time in firemonkey?

我在 Delphi XE7 中使用 JSON XSuperObject 和从 Web API 检索数据的 Firemonkey 在 Android 应用程序中遇到性能速度问题。 =11=]

我的场景是一个系统排名table,每次迭代在运行时创建 29 个控件,有时玩家数量应该超过 90,所以每次迭代 (90 * 27) 它创建 2610~ 个控件在运行时。 在 Windows 平台上测试需要 3 秒,但在 Android 的移动平台上需要 17 秒。我知道这会影响应用程序的性能,但我不知道 Windows 和 Android.

的加载时间有显着差异

那么有什么方法可以减少加载时间或优化下面的代码以获得最佳性能吗?谢谢。

亲切的问候。

{Controls to create at runtime;

1 TLayout as parent of the controls (1 control).

1 TLine at bottom of TLayout to separate layouts (+1 control)

1 TPanel with a TImage for the player avatar and a TLabel for the player name (+3 controls).

1 TPanel with a TButton to display details (+2 controls).

1 TPanel with a THorzScrollBox containing 10 TLabels inside of 10 TRectangle as parent  to scroll and display the points of the round (+22 controls).

Overall of 29 controls to create at runtime in each iteration.}

procedure TForm1.RankingClick(Sender: TObject);
var
        JsonObjHC: ISuperObject;
        JsonArrHC: ISuperArray;
        JsonStrHC, URL_IRkC, Pais: String;
        Retriever: TIdHTTP;
        x, z: integer;
        Before, After, Total:  TDateTime;
begin
        URL_IRkC := 'web api URL here ….';
        Retriever := TIdHTTP.Create(nil);
        try
             JsonStrHC := Retriever.Get(URL_IRkC);
        finally
             Retriever.DisposeOf;
        end;
        JsonArrHC := SA(JsonStrHC);
        Before := Time;  // to check seconds before loop starts
        LytMainRk.BeginUpdate;   //Main layout that contains all controls.
        for x := 0 to JsonArrHC.Length-1 do
        begin
              JsonObjHC := JsonArrHC.O[x];
              // proceddure that creates controls in each iteration   
              Ranking_Table (JsonObjHC.S['Image'], JsonObjHC.S['Name'], JsonObjHC.I['R1'], JsonObjHC.I['R2'], JsonObjHC.I['R3'], JsonObjHC.I['R4'], JsonObjHC.I['R5'], JsonObjHC.I['R6'], JsonObjHC.I['R7'], JsonObjHC.I['R8'], JsonObjHC.I['R9'], JsonObjHC.I['R10'], x, z);
              inc(z, 28);
        end;
        LytMainRk.EndUpdate;
        Total := Before - After;
        SecondsBetween(ShowMessage(DateToStr(Total)); // seconds after loop finishes, 3 secs. on Windows, 17 secs. on Android
end;


procedure TForm1.Ranking_Table(Avatar, NameP: String;  R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, x, z: integer);
var
    RectHC_R1, RectHC_R2, RectHC_R3, RectHC_R4, RectHC_R5, RectHC_R6, RectHC_R7, RectHC_R8, RectHC_R9, RectHC_R10: TRectangle;
    PanelHC, PanelHC1, PanelHC2: TPanel;
    ImageAvatarHC: TImage;
    LineaHC: TLine;
    LNameHC, LabelHC_R1, LabelHC_R2, LabelHC_R3, LabelHC_R4, LabelHC_R5, LabelHC_R6, LabelHC_R7, LabelHC_R8, LabelHC_R9, LabelHC_R10: TLabel;
    LayoutHC: TLayout;
    BotonHC: TButton;
    HorzScrollBoxHC: THorzScrollBox;
begin
    LayoutHC := TLayout.Create(Self);
    LayoutHC.Name := 'LayoutHC' + x.ToString;
    LayoutHC.Align := TAlignLayout.Top;
    LayoutHC.Margins.Left := 6;
    LayoutHC.Margins.Right := 6;
    LayoutHC.Margins.Top := 0;
    LayoutHC.Position.Y := z;
    LayoutHC.Height := 28;
    LayoutHC.Parent := LyHistorialC;
    LineaHC := TLine.Create(Self);
    LineaHC.Name := 'LineaHC' + x.ToString;
    LineaHC.Align := TAlignLayout.MostBottom;
    LineaHC.LineType := TLineType.Top;
    LineaHC.Height := 1;
    LineaHC.Stroke.Color := $FF708090;
    LineaHC.Stroke.Thickness := 1;
    LineaHC.Parent := LayoutHC;
    PanelHC := TPanel.Create(Self);
    PanelHC.Name := 'PanelHC_' + x.ToString;
    PanelHC.Align := TAlignLayout.MostLeft;
    PanelHC.Width := 126;
    PanelHC.Parent := LayoutHC;
    ImageAvatarHC := TImage.Create(Self);
    ImageAvatarHC.Name := ' ImageAvatarHC ' + x.ToString;
    ImageAvatarHC.Align := TAlignLAyout.Left;
    ImageAvatarHC.Margins.Left := 4;
    ImageAvatarHC.Margins.Right := 2;
    ImageAvatarHC.Width := 28;
    load_image_from_resource(ImageAvatarHC, Avatar);
    ImageAvatarHC.Parent := PanelHC;
    LNameHC := TLabel.Create(Self);
    LNameHC.Name := ' LNameHC ' + x.ToString;
    LNameHC.Align := TAlignLayout.Client;
    LNameHC.Margins.Left := 2;
    LNameHC.AutoSize := True;
    LNameHC.TextSettings.FontColor := $FF000000;
    LNameHC.TextSettings.Font.Size := 10;
    LNameHC.StyledSettings := [];
    LNameHC.Text := NameP;
    LNameHC.Parent := PanelHC;
    PanelHC1 := TPanel.Create(Self);
    PanelHC1.Name := 'PanelHC1' + x.ToString;
    PanelHC1.Align := TAlignLayout.Left;
    PanelHC1.Width := 26;
    PanelHC1.Parent := LayoutHC;
    BotonHC := TButton.Create(Self);
    BotonHC.Name := 'BotonHC' + x.ToString;
    BotonHC.Align := TAlignLayout.Client;
    BotonHC.TextSettings.Font.Style := [TFontStyle.fsBold];
    BotonHC.Text := '>';
    BotonHC.OnClick := ClickHistorialC;
    BotonHC.Parent := PanelHC1;
    PanelHC2 := TPanel.Create(Self);
    PanelHC2.Name := 'PanelHC2' + x.ToString;
    PanelHC2.Align := TAlignLayout.Client;
    PanelHC2.Parent := LayoutHC;
    HorzScrollBoxHC := THorzScrollBox.Create(Self);
    HorzScrollBoxHC.Name := 'HorzScrollBoxHC' + x.ToString;
    HorzScrollBoxHC.Align := TAlignLayout.Client;
    HorzScrollBoxHC.ShowScrollBars := False;
    HorzScrollBoxHC.Parent := PanelHC2;

    RectHC_R1 := TRectangle.Create(Self);
    RectHC_R1.Name := 'RectHC_R1' + x.ToString;
    RectHC_R1.Align := TAlignLayout.Left;
    RectHC_R1.Fill.Color := $FF1E90FF;
    RectHC_R1.Margins.Bottom := 2;
    RectHC_R1.Margins.Left := 2;
    RectHC_R1.Margins.Top := 2;
    RectHC_R1.Sides := [];
    RectHC_R1.Stroke.Kind := TBrushKind.None;
    RectHC_R1.Width := 23;
    RectHC_R1.XRadius := 4;
    RectHC_R1.YRadius := 4;
    RectHC_R1.Parent := HorzScrollBoxHC;
    LabelHC_R1 := TLabel.Create(Self);
    LabelHC_R1.Name := ' LabelHC_R1' + x.ToString;
    LabelHC_R1.Align := TAlignLayout.Client;
    LabelHC_R1.AutoSize := True;
    LabelHC_R1.TextSettings.FontColor := $FFFFFFFF;
    LabelHC_R1.TextSettings.Font.Size := 11;
    LabelHC_R1.TextSettings.HorzAlign := TTextAlign.Center;
    LabelHC_R1.StyledSettings := [];
    LabelHC_R1.Text := R1.ToString;
    LabelHC_R1.Parent := RectHC_R1;
   {  ………………….
              Up to 8 TRectangles and TLabels to create here…
             …………………….  }
    RectHC_R10 := TRectangle.Create(Self);
    RectHC_R10.Name := 'RectHC_R10' + x.ToString;
    RectHC_R10.Align := TAlignLayout.Left;
    RectHC_R10.Fill.Color := $FF1E90FF;
    RectHC_R10.Margins.Bottom := 2;
    RectHC_R10.Margins.Left := 2;
    RectHC_R10.Margins.Top := 2;
    RectHC_R10.Sides := [];
    RectHC_R10.Stroke.Kind := TBrushKind.None;
    RectHC_R10.Width := 23;
    RectHC_R10.XRadius := 4;
    RectHC_R10.YRadius := 4;
    RectHC_R10.Parent := HorzScrollBoxHC;
    LabelHC_R10 := TLabel.Create(Self);
    LabelHC_R10.Name := ' LabelHC_R10' + x.ToString;
    LabelHC_R10.Align := TAlignLayout.Client;
    LabelHC_R10.AutoSize := True;
    LabelHC_R10.TextSettings.FontColor := $FFFFFFFF;
    LabelHC_R10.TextSettings.Font.Size := 11;
    LabelHC_R10.TextSettings.HorzAlign := TTextAlign.Center;
    LabelHC_R10.StyledSettings := [];
    LabelHC_R10.Text := R10.ToString;
    LabelHC_R10.Parent := RectHC_R1;
end;

使用那么多控件,您将永远无法获得可接受的速度,尤其是在移动设备上。

对于矩形、文本、线条...我只使用自定义绘画。您可以使用带有 OnPaint 事件的 PaintBox。

procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
begin
  Canvas.Fill.Color := $FF1E90FF;
  Canvas.FillRect(RectF(10, 10, 200, 50), 4, 4, [], 1.0);
  Canvas.Fill.Color := $FFFFFFFF;
  Canvas.Font.Size := 13.0;
  Canvas.FillText(RectF(10, 10, 200, 50), 'My Text', True, 1.0, [], TTextAlign.Center, TTextAlign.Center);
end;

只要需要更新屏幕,就会调用此事件。如果您的数据已更改并且您想要更新屏幕,请调用 PaintBox1.InvalidateRect({...area that needs to be updated});。这将触发屏幕更新。

按钮有点棘手,您必须使用 OnMouseDown 和 OnMouseUp 事件并手动评估鼠标点击。

在长 运行 中,拥有自己的控件可能有意义,该控件派生自 TControlTStyledControl,在重写的 Paint 方法中绘制。