Xamarin的Andr​​oid终结没有得到所谓的离开活动时,要到另一个活动要到、Xamarin、Andr、oid

2023-09-06 03:33:47 作者:注定逃離不了

终结永远不会离开活动后调用。这是否意味着该活动还活着,即使我转移到下一个活动。

 命名空间XamarinTest {
[活动(标签=XamarinTest,图标=@可绘制/图标)]
公共类MainActivity:活动{
    私人诠释计数= 1;

    私人TextView的密度;

    保护覆盖无效的OnCreate(束捆){
        base.OnCreate(包);
        //从主的布局资源设置我们的观点
        的setContentView(Resource.Layout.ScreenData);
        密度= FindViewById< TextView的>(Resource.Id.Density);

        VAR pendingInent =新意图();
        pendingInent.SetFlags(ActivityFlags.ClearTop);
        pendingInent.SetClass(此的typeof(TestActivity));
        StartActivity(pendingInent);
        完();
    }


    〜MainActivity(){

        Console.WriteLine(终结称为);
    }

  保护覆盖无效的Dispose(BOOL处置){
        如果(处置){
            density.Dispose();
            密度=无效;
        }
        base.Dispose(处置);
    }

  }
}
 

解决方案

这其实是非常复杂的;简答题,关于活动仍然活着,是yes和no。提供您已经清除了资源为你的活动正确,你的活动将被清理(最终)被垃圾收集器。

关于清理,它的进口要知道,Xamarin鼓励(幻灯片44起)使用的终结。这里的原因:

     在他们不能保证在任何最后期限运行。   在他们不以特定的顺序运行。   在他们使物体活得更长。   的GC不知道非托管资源。   

因此​​,使用终结执行清理是做事情的方法不对...如果你想确保 MainActivity 被破坏,人工处理的活动在它的的OnDestroy 回调:

 保护覆盖无效的OnDestroy()
{
    base.OnDestroy();
    this.Dispose(); // Sever的Java绑定。
}
 

这将导致单声道打破peer对象连接,并在接下来的垃圾收集周期破坏活动( GC.Collect的(GC.MaxGeneration))。从文档:

  

要缩短对象的生命周期,Java.Lang.Object.Dispose()被调用。通过释放的全球参考,从而使要收集的对象更快,这将手动断绝的两个VM之间的对象上的连接。

请注意来电订购那里, this.Dispose() 必须被称为的在的任何code调用返回到Android的土地。为什么?所有的Java和.NET之间的连接正在打破,让Android的回收资源,使采用Android陆对象的任何code(片段,活动,适配器)将失败。

现在,到一些调试技术活动泄漏。要验证您的行为将被清空,添加以下code到您的应用程序项的的OnCreate 方法活动

  VAR vmPolicy =新StrictMode.VmPolicy.Builder();
StrictMode.SetVmPolicy(vmPolicy.DetectActivityLeaks()PenaltyLog()建立());
 

这使轮流StrictMode,一个非常有用的调试工具,它高兴地通知你,当你已经泄露的资源。当您的应用程序的活动之一是不正确释放,将倾倒这样的事情到输出流:

  [StrictMode]类activitydispose.LeakyActivity;实例= 2;极限= 1
[StrictMode] android.os.StrictMode $ InstanceCountViolation:类activitydispose.LeakyActivity;实例= 2;极限= 1
[StrictMode]在android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)
 

的Dispose()通话复合使用,你可以检查活动正在释放。以下是您最好的活动及其资源Xamarin.Android:

 保护覆盖无效的Dispose(BOOL处置)
{
    // TODO:在此处处置逻辑。
    base.Dispose(处置);
    所以GC.Collect(GC.MaxGeneration); //将强制清理,但不建议使用。
}

保护覆盖无效的OnDestroy()
{
    如果(密度!= NULL){//发布Java对象(按钮,适配器等)在这里
        density.Dispose();
        密度=无效;
    }
    base.OnDestroy();
    this.Dispose(); // Sever的Java绑定。
}
 

The Finalizer is never called after leaving the activity. Does that mean the activity is still alive even though I moved on to the next 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);
    }

  }
}

解决方案

This is actually remarkably complicated; the short answer, regarding the activity still being alive, is yes and no. Providing you have cleaned up the resources for your Activity correctly, your activity will be cleaned up (eventually) by the garbage collector.

Regarding cleanup, it's import to know that Xamarin discourages (slide 44 onwards) using finalizers. Here's why:

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.

Therefore, using a finalizer to perform cleanup is the wrong way of doing things... If you want to ensure that MainActivity is destroyed, manually dispose the Activity in it's OnDestroy callback:

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

This will cause Mono to break the peer object connection and destroy the activity during the next garbage collection cycle (GC.Collect(GC.MaxGeneration)). From the docs:

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.

Note the call order there, this.Dispose() must be called after any code that invokes back into Android land. Why? All the connections between Java and .NET are now broken to allow Android to reclaim resources so any code that uses Android-land objects (Fragment, Activity, Adapter) will fail.

Now, onto some debugging techniques for Activity leaks. To verify that your activity is being cleaned up, add the following code to the OnCreate method of your apps entry Activity:

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

This enables turns on StrictMode, an extremely useful debugging tool that happily informs you when you've leaked resources. When one of your apps activities isn't released correctly, it will dump something like this to the output stream:

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

Combining this with the Dispose() call, you can check that activities are being released. Here is how you'd typically an Activity and its resources 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.
}