c# - El Finalizador de Android Xamarin no se llama cuando sale de la actividad para ir a otra actividad
finalizer (1)
Esto es realmente notablemente complicado; la respuesta corta, con respecto a la actividad que aún está viva, es sí y no. Siempre que haya limpiado los recursos para su Activity
correctamente, su actividad será limpiada (eventualmente) por el recolector de basura.
En cuanto a la limpieza, es importante saber que Xamarin lo desalienta (diapositiva 44 en adelante) usando los finalizadores. Este es el por qué:
- No están garantizados para ejecutarse dentro de cualquier fecha límite.
- No se ejecutan en una secuencia específica.
- Hacen que los objetos vivan más tiempo.
- El GC no sabe sobre recursos no administrados.
Por lo tanto, usar un finalizador para realizar la limpieza es la forma incorrecta de hacer las cosas ... Si desea asegurarse de que se destruya la Activity
, elimine manualmente la Activity
en su devolución de llamada OnDestroy
:
protected override void OnDestroy ()
{
base.OnDestroy ();
this.Dispose (); // Sever java binding.
}
Esto hará que Mono rompa la conexión del objeto par y destruya la actividad durante el siguiente ciclo de recolección de basura ( GC.Collect(GC.MaxGeneration)
). De los documentos:
Para acortar la duración del objeto, debe invocarse Java.Lang.Object.Dispose (). Esto "cortará" manualmente la conexión en el objeto entre las dos máquinas virtuales al liberar la referencia global, permitiendo así que los objetos se recojan más rápido.
Tenga en cuenta el orden de las llamadas allí, this.Dispose()
debe llamarse después de cualquier código que invoca de nuevo en Android land. ¿Por qué? Todas las conexiones entre Java y .NET ahora están rotas para permitir que Android recupere recursos, por lo que cualquier código que use objetos de Android (Fragmento, Actividad, Adaptador) fallará.
Ahora, sobre algunas técnicas de depuración para fugas de actividad. Para verificar que su actividad se esté limpiando, agregue el siguiente código al método OnCreate
de su Activity
entrada de aplicaciones:
var vmPolicy = new StrictMode.VmPolicy.Builder ();
StrictMode.SetVmPolicy (vmPolicy.DetectActivityLeaks().PenaltyLog().Build ());
Esto habilita StrictMode
, una útil herramienta de depuración que le informa con alegría cuando ha filtrado recursos. Cuando una de sus actividades de aplicaciones no se lanza correctamente, arrojará algo así a la secuencia de salida:
[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)
Combinando esto con la llamada Dispose()
, puede verificar que se están liberando actividades. Así es como normalmente una Activity
y sus recursos en 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.
}
El Finalizador nunca se llama después de abandonar la actividad. ¿Eso significa que la actividad todavía está viva a pesar de que pasé a la siguiente actividad?
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);
}
}
}