2015-03-04 5 views
8

Der Finalizer wird nach dem Verlassen der Aktivität nie aufgerufen. Bedeutet das, dass die Aktivität noch am Leben ist, obwohl ich zur nächsten Aktivität übergegangen bin?Xamarin Android Finalizer wird nicht aufgerufen, wenn die Aktivität verlassen wird, um zu einer anderen Aktivität zu wechseln

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

    } 
} 

Antwort

26

Dies ist tatsächlich bemerkenswert kompliziert; Die kurze Antwort bezüglich der noch lebenden Aktivität ist Ja und Nein. Wenn Sie die Ressourcen für Ihre Activity korrekt bereinigt haben, wird Ihre Aktivität (eventuell) vom Garbage Collector bereinigt.

In Bezug auf die Bereinigung ist es wichtig zu wissen, dass Xamarin discourages (slide 44 onwards) Finalizer verwenden. Hier ist der Grund:

  • Sie sind nicht innerhalb einer Frist laufen garantiert.
  • Sie laufen nicht in einer bestimmten Reihenfolge.
  • Sie machen Objekte länger leben.
  • Der GC weiß nicht über nicht verwaltete Ressourcen.

daher einen Finalizer mit Bereinigung durchzuführen, ist der falsche Weg, Dinge zu tun ... Wenn Sie sicherstellen möchten, dass MainActivity zerstört wird, manuell den Activity entsorgen es OnDestroy Rückruf ist:

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

Dadurch wird Mono die Verbindung peer object unterbrechen und die Aktivität während des nächsten Speicherbereinigungszyklus (GC.Collect(GC.MaxGeneration)) zerstören. Aus der Dokumentation:

Um die Lebensdauer des Objekts zu verkürzen, sollte Java.Lang.Object.Dispose() aufgerufen werden. Dies wird die Verbindung auf dem Objekt zwischen den beiden VMs manuell "trennen", indem die globale Referenz freigegeben wird, wodurch die Objekte schneller gesammelt werden können.

Hinweis gibt den Abrufauftrag, this.Dispose()mussnach aufgerufen wird jeder Code, der wieder in Android Land aufruft. Warum? Alle Verbindungen zwischen Java und .NET sind nun unterbrochen, um es Android zu ermöglichen, Ressourcen zurückzugewinnen, so dass jeder Code, der Android-Land-Objekte (Fragment, Aktivität, Adapter) verwendet, fehlschlägt.

Nun zu einigen Debugging-Techniken für Aktivität Lecks. Um sicherzustellen, dass Ihre Aktivität gereinigt wird, fügen Sie den folgenden Code in die OnCreate Methode Ihrer Apps Eintrag Activity:

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

Dies ermöglicht StrictMode, ein nützliches Debugging-Tool, das informiert Sie gerne, wenn Sie Ressourcen geleckt haben. Wenn einer Ihrer Apps Aktivitäten nicht korrekt freigegeben, wird es so etwas wie dies in den Ausgabestream Dump:

[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) 

In Kombination mit dem Dispose() Anruf, können Sie prüfen, ob Tätigkeiten freigegeben werden. Hier ist, wie Sie normalerweise eine Activity und ihre Ressourcen in 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. 
} 
+5

"Das ist eigentlich bemerkenswert kompliziert" <------ jede Antwort, die damit beginnt, wird eine gute sein. – rarrarrarrr

+0

Diese Info ist sehr nützlich. StrictMode rockt – xleon

Verwandte Themen