【问题标题】:Xamarin Android Finalizer not getting called when leaving the activity to go to another Activity离开活动去另一个活动时,Xamarin Android Finalizer 没有被调用
【发布时间】:2015-05-05 22:46:44
【问题描述】:

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

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);
    }

  }
}

【问题讨论】:

    标签: c# android xamarin finalizer


    【解决方案1】:

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

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

    • 不保证它们会在任何期限内运行。
    • 它们不按特定顺序运行。
    • 它们使对象寿命更长。
    • GC 不知道非托管资源。

    因此,使用终结器执行清理是错误的处理方式...如果要确保 MainActivity 被销毁,请在其 OnDestroy 回调中手动处置 Activity

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

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

    为了缩短对象的生命周期,应该调用 Java.Lang.Object.Dispose()。这将通过释放全局引用手动“切断”两个 VM 之间对象上的连接,从而更快地收集对象。

    注意那里的调用顺序,this.Dispose()必须在调用回 Android 领域的任何代码之后调用。为什么? Java 和 .NET 之间的所有连接现在都已断开,以允许 Android 回收资源,因此任何使用 Android 领域对象(Fragment、Activity、Adapter)的代码都会失败。

    现在,介绍一些针对 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() 调用相结合,您可以检查是否正在发布活动。以下是您通常如何在 Xamarin.Android 中使用 Activity 及其资源:

    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.
    }
    

    【讨论】:

    • “这实际上非常复杂”
    • 这个信息非常有用。 StrictMode 摇滚
    • StrictMode 似乎只适用于活动,我们是否也可以为 Fragments 做到这一点?因为它确实像 StrictMode 一样不显示任何有关 Fragments 的泄漏信息。
    猜你喜欢
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多