如何在 Xamarin.Android 中删除对话框中的所有引用(潜在的内存泄漏)?

How to remove all references from a Dialog on dismiss in Xamarin.Android (potential memory leak)?

我想我有内存泄漏,因为在我打开一个特定的 Dialog 并更改为一个新的 Activity 后,应用程序在没有任何警告的情况下崩溃并且 Visual Studio/App 没有任何警告就停止了如动画 gif 中所示,出现警告或特定行:

第二个动画 gif 是我在 Visual Studio 中调试应用程序的地方,然后突然停止。该应用程序在没有意义的行中完成 base.OnDrawerSlide(drawerView, slideOffset):

现在,对话框非常重,因为它实时进行一些数学计算:

对话:

private void BtnCompareAll_Click(object sender, EventArgs e)
{
    GravityPlanets gInfo = new();
    View dialogView = LayoutInflater.Inflate(Resource.Layout.CompareAll, null);
    var Dialog = new Android.App.AlertDialog.Builder(Context);

    int firstCelestialLoc = GetItemPosition(planets, SpinnerFirstCelestial.Text);
    var gravity = new Supernova.Core.Gravity();

    var listView = dialogView.FindViewById<ListView>(Resource.Id.lstCelestialObjects);
    var textObject1 = dialogView.FindViewById<TextView>(Resource.Id.textObject1);
    var imgView = dialogView.FindViewById<ImageView>(Resource.Id.imgCObject);
    var yourWeight = dialogView.FindViewById<TextView>(Resource.Id.yourWeight);

    imgView.SetImageDrawable(compareAllList[firstCelestialLoc].image);

    textObject1.Text = SpinnerGravityUnits.Text == gUnits[0]
        ? $"{planets[firstCelestialLoc]}, {GetCelestialObject(gInfo.CelestialObjectType(firstCelestialLoc))}, {gInfo.GetGravity(firstCelestialLoc)} {SpinnerGravityUnits.Text}"
        : $"{planets[firstCelestialLoc]}, {GetCelestialObject(gInfo.CelestialObjectType(firstCelestialLoc))}, {Math.Round(gravity.ChangeToFeet(gInfo.GetGravity(firstCelestialLoc)), 3)} {SpinnerGravityUnits.Text}";

    List<DrawerData> currentObjects = compareAllList.DeepClone();
    currentObjects.RemoveAt(firstCelestialLoc);

    bool isNumeric = double.TryParse(TxtWeight.Text, out double earthWeight);
    if (isNumeric && earthWeight > 0)
    {
        yourWeight.Visibility = ViewStates.Visible;
        yourWeight.Text = $"{GetString(Resource.String.lblYourWeight)} {TxtWeight.Text}{SpinnerWeightUnits.Text}";
    }
    else
    {
        yourWeight.Visibility = ViewStates.Gone;
        yourWeight.Text = "";
    }

    GravityPlanets gPlanets = new();

    for (int i = 0; i < currentObjects.Count(); i++)
    {
        var secondG = GetItemPosition(planets, currentObjects[i].name);
        var gPercentage = Math.Round(gInfo.PercentageGravity(firstCelestialLoc, secondG), 0);

        switch (gInfo.ComparedGravity(firstCelestialLoc, secondG))
        {
            case 0:
                gravType = GetString(Resource.String.gravLower);
                currentObjects[i].color = "#43A047";
                break;
            default:
                gravType = GetString(Resource.String.gravGreater);
                currentObjects[i].color = "#F44336";
                break;
        }

        var gravVal = SpinnerGravityUnits.Text == gUnits[0] ? gInfo.GetGravity(secondG) : Math.Round(gravity.ChangeToFeet(gInfo.GetGravity(secondG)), 3);

        currentObjects[i].name = $"<b>{currentObjects[i].name}, {GetCelestialObject(gInfo.CelestialObjectType(secondG))}</b><br>{gravVal} {SpinnerGravityUnits.Text}, {string.Format(gravType, gPercentage)}";

        if (isNumeric && earthWeight > 0)
        {
            currentObjects[i].name += $"<br>{GetString(Resource.String.lblYourWeightCO)} {GetNewWeight(gPlanets, double.Parse(TxtWeight.Text), firstCelestialLoc, secondG)} {SpinnerWeightUnits.Text}";
        }

        var adapter = new CompareAllAdapter(currentObjects);

        listView.Adapter = adapter;

        Dialog.SetView(dialogView);

        Dialog.SetOnDismissListener(new OnDismissListener());

        Dialog.Show();
    }
}

我用这个 class 来“处理”对话框:

关闭 class:

private class OnDismissListener : Java.Lang.Object, IDialogInterfaceOnDismissListener
{
    public void OnDismiss(IDialogInterface dialog)
    {
        dialog.Dispose();
    }
}

奇怪的是,它似乎没有得到妥善处理,因为我可以打开其他对话框但没有任何反应,这是唯一导致这种异常行为的对话框。

此外,我试图通过将对话框的值设为空同时将其设为 属性 来删除它的引用,但失败了。我也尝试过使用垃圾收集器,但也失败了,因为它使应用程序崩溃了。

我什至尝试避免在 MainActivity class:

中使用它来存储任何历史记录

[Android.App.Activity(Label = "Gravity Now!", MainLauncher = true, Icon = "@drawable/ic_icon", NoHistory = true)]

我什至创建了一个额外的 OnCancelListener,我什至在其中处理 DialogView 而没有任何结果:

Dialog.SetOnCancelListener(new OnCancelListener(dialogView));

private class OnCancelListener : Java.Lang.Object, IDialogInterfaceOnCancelListener
{
    private View dialogView;

    public OnCancelListener(View dialogView)
    {
        this.dialogView = dialogView;
    }

    public void OnCancel(IDialogInterface dialog)
    {
        dialogView.Dispose();
        dialogView = null;
        dialog.Dispose();
        dialog = null;
    }
}

如需了解更多信息,请查看完整源代码:

https://bitbucket.org/supernovaic/gnow-android/src/master/

此外,我得到了这个崩溃文件,但找不到任何有用的东西:

https://drive.google.com/file/d/10-wmY337mG_k6ZoS7GAcFI1reR6eqQRy/view?usp=sharing

这些是最后几行:

09-11 18:19:26.889 28140 31014 I ActivityManager: Force stopping tk.supernova.gnow appid=10156 user=0: from pid 13171 09-11 18:19:26.892 28785 28785 I AppBase : AppBase.onTrimMemory():615 onTrimMemory(): 5 09-11 18:19:26.894 13171 13174 I cmd : oneway function results will be dropped but finished with status OK and parcel size 4 09-11 18:19:26.935 28785 28785 I GoogleInputMethodService: GoogleInputMethodService.onTrimMemory():4225 onTrimMemory(): 5 09-11 18:19:26.951 28140 28158 W ActivityManager: setHasOverlayUi called on unknown pid: 12844 09-11 18:19:26.953 28140 28158 W ActivityTaskManager: Activity top resumed state loss timeout for ActivityRecord{3c51759 u0 tk.supernova.gnow/crc64c3564668e399e885.Help t-1 f}}

此时,我不知道还能做什么。知道我做错了什么吗?

P.S.:

更新:

我从另一个人那里得到了这个答案 forum:

LeonLu-MSFT

In the DefinitionFragment.cs file on line 36 in the LoadGif() function, you could try to use the GetBuffer() method in-place of the ToArray() method.

Please refer to this document for further explanations: MemoryStream.ToArray Method (System.IO) | Microsoft Docs

现在,它加载了帮助,但在选项卡之间再次无故崩溃。顺便说一句,我在两个选项卡中都更改为GetBuffer()

我发现错误在这里:

List<DrawerData> currentObjects = compareAllList.DeepClone();

我不得不更改逻辑并以不同的方式创建临时数据:

private List<DrawerData> GetPlanetsData()
{
    return new List<DrawerData>()
    {
        new DrawerData() {
            name = GetString(Resource.String.itemSun),
            image = GetCelestialObjectDrawable(Resource.Drawable.sun),
            url = GetString(Resource.String.itemWikiSun)
        },
        new DrawerData() {
            name = GetString(Resource.String.itemMercury),
            image = GetCelestialObjectDrawable(Resource.Drawable.mercury),
            url = GetString(Resource.String.itemWikiMercury)
        },
        new DrawerData() {
            name = GetString(Resource.String.itemVenus),
            image = GetCelestialObjectDrawable(Resource.Drawable.venus),
            url = GetString(Resource.String.itemWikiVenus)
        }
        //...
    };
}

List<DrawerData> currentObjects = GetPlanetsData();

似乎无法删除创建的 Deep Cloner 数据。