Xamarin Android 离开 activity 去另一个 Activity 时没有调用终结器

Xamarin Android Finalizer not getting called when leaving the activity to go to another Activity

离开 activity 后永远不会调用终结器。这是否意味着 activity 仍然存在,即使我移动到下一个 activity。

namespace XamarinTest {
[Activity(Label = "XamarinTest", Icon = "@drawable/icon")]
public class MainActivity : Activity {
    private int count = 1;

    private TextView density;

    protected override void OnCreate(Bundle bundle) {
        base.OnCreate(bundle);
        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.ScreenData);
        density = FindViewById<TextView>(Resource.Id.Density);

        var pendingInent = new Intent();
        pendingInent.SetFlags(ActivityFlags.ClearTop);
        pendingInent.SetClass(this, typeof(TestActivity));
        StartActivity(pendingInent);
        Finish();
    }


    ~MainActivity() {

        Console.WriteLine("Finalizer called");
    }

  protected override void Dispose(bool disposing){
        if (disposing) {
            density.Dispose();
            density = null;
        }
        base.Dispose(disposing);
    }

  }
}

这实际上非常复杂;关于 activity 还活着,简短的回答是肯定和否定。如果您已正确清理 Activity 的资源,垃圾收集器将(最终)清理您的 activity。

关于清理,知道 Xamarin discourages (slide 44 onwards) 使用终结器很重要。原因如下:

  • They are not guaranteed to run within any deadline.
  • They don't run in a specific sequence.
  • They make objects live longer.
  • The GC doesn't know about unmanaged resources.

因此,使用终结器执行清理是错误的做事方式...如果要确保 MainActivity 被销毁,请手动处理 Activity 中的 [=17] =]回调:

protected override void OnDestroy ()
{
    base.OnDestroy ();
    this.Dispose (); // Sever java binding.
}

这将导致 Mono 在下一个垃圾收集周期 (GC.Collect(GC.MaxGeneration)) 中中断 peer object 连接并销毁 activity。来自文档:

To shorten object lifetime, Java.Lang.Object.Dispose() should be invoked. This will manually "sever" the connection on the object between the two VMs by freeing the global reference, thus allowing the objects to be collected faster.

注意那里的调用顺序,this.Dispose() 必须 被调用 任何调用回 [=51= 的代码之后] 土地。为什么? Java 和 .NET 之间的所有连接现已断开,以允许 Android 回收资源,因此任何使用 Android-land 对象(片段、Activity、适配器)的代码都将失败。

现在,介绍一些针对 Activity 泄漏的调试技术。要验证您的 activity 是否正在清理,请将以下代码添加到应用条目 ActivityOnCreate 方法中:

var vmPolicy = new StrictMode.VmPolicy.Builder ();
StrictMode.SetVmPolicy (vmPolicy.DetectActivityLeaks().PenaltyLog().Build ());

这会启用 StrictMode,这是一个有用的调试工具,它会在您泄漏资源时愉快地通知您。当您的某个应用活动未正确发布时,它会将类似这样的内容转储到输出流:

[StrictMode] class activitydispose.LeakyActivity; instances=2; limit=1
[StrictMode] android.os.StrictMode$InstanceCountViolation: class activitydispose.LeakyActivity; instances=2; limit=1
[StrictMode]    at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

将此与 Dispose() 调用相结合,您可以检查活动是否正在发布。以下是您通常如何 Activity 及其在 Xamarin.Android 中的资源:

protected override void Dispose (bool disposing)
{
    // TODO: Dispose logic here.
    base.Dispose (disposing);
    GC.Collect(GC.MaxGeneration); // Will force cleanup but not recommended.
}

protected override void OnDestroy ()
{
    if (density != null) { // Release Java objects (buttons, adapters etc) here
        density.Dispose ();
        density = null;
    }
    base.OnDestroy ();
    this.Dispose (); // Sever java binding.
}