android - 在 Android 中释放动态创建的控件

标签 android delphi firemonkey

在我的 Firemonkey 多平台应用程序中,我动态创建了一些控件。使用后,我会销毁它们。

在 Windows 中,这个动态创建和销毁的进程没有问题。但是,在 Android 中,下面的代码似乎不会破坏控件,因为会弹出一个错误提示控件已经存在(当我尝试重新创建控件时,我确实看到旧控件仍然存在)。

我如何确保控件在 Android(和/或 iOS - 我认为它与 iOS 类似)中被正确销毁?

for i := oParentRect.ControlsCount-1 downto 0 do
begin
  oControl := oParentRect.Controls[i];
  if (oControl is TText)
     or (oControl is TEdit)
     then
     begin           
       FreeAndNil( oControl );
       // I have also tried oControl.Free;
     end;
end;

最佳答案

在 RAD Studio 10.4 之前,Delphi 使用 ARC (Automatic Reference Counting)用于 iOS 和 Android 平台上的对象生命周期管理。在 ARC 下,TObject.Free()FreeAndNil() 的行为与您预期的不同。它们被编译器翻译成纯粹的 nil 赋值,减少对象的引用计数。一个对象在其引用计数降为 0 之前不会被释放。

在您的示例中,所讨论的对象有多个引用(在 Controls[] 列表和 oControl 变量中),因此 FreeAndNil( ) 没有达到预期的效果,因为它只是将 oControl 变量设置为 nil 而不是从 Controls[] 列表中删除对象。换句话说,您的示例实际上与以下示例相同:

for i := oParentRect.ControlsCount-1 downto 0 do
begin
  oControl := oParentRect.Controls[i]; // <-- increments refcnt
  if (oControl is TText) or (oControl is TEdit) then
  begin           
    //FreeAndNil( oControl );
    oControl := nil; // <-- decrements refcnt
  end;
end;

如果你真的想在 ARC 下编码时立即销毁一个对象,你需要使用 TObject.DisposeOf()相反,例如:

for i := oParentRect.ControlsCount-1 downto 0 do
begin
  oControl := oParentRect.Controls[i]; // <-- increments refcnt
  if (oControl is TText) or (oControl is TEdit) then
  begin           
    //FreeAndNil( oControl );
    oControl.DisposeOf; // <-- destroys object, but does not free its memory yet
    oControl := nil; // <-- decrements refcnt
  end;
end;

在这种模型下,当一个对象被“处置”时,它的析构函数会立即被调用,但它的底层内存块还没有被释放。引用计数仍然发生在 block 上。该对象位于 "disposed" 中状态,直到它的引用计数降为 0,然后释放内存块。不再调用析构函数。

此行为记录在 Embarcadero 的 DocWiki 上:The Free and Dispose Of methods under ARC

现在,话虽如此,在 RAD Studio 10.4 中,Embarcadero has removed object ARC handling completely ,回到传统的内存管理模型(他们现在称之为“统一内存管理”)。在这种情况下,TObject.Free()FreeAndNil() 现在的行为与它们在非移动平台上的行为一样,但现在在所有平台上都是一样的。因此,您的原始代码现在将按预期工作,您无需在 10.4 之后切换到 TObject.DisposeOf()(不过,如果您愿意,可以,它的行为与 完全相同TObject.Free(),如果你需要支持 10.3 及更早版本,给你想要的效果)。

关于android - 在 Android 中释放动态创建的控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62540072/

相关文章:

delphi - 从 Firemonkey Delphi Windows 将句柄传递给 LibVLC

delphi - 为什么在设置 IHTMLInputTextElement 的值时会出现访问冲突?

sql - 如何监控我的 Delphi 应用程序执行的 SQL?

ios - 带有 Indy 或第三方 Internet 组件的 iOS 上的 Delphi XE2

java - onActivityResult 改变我当前的 fragment

delphi - 如何将alignof翻译成Delphi?

delphi - 如何在 TMemo 组件中水平居中文本?

java - 从代码中激活删除键

Android:将图像添加到电子邮件的撰写正文

android - FAB 隐藏在 Bottom Sheet 下