c# - Android 上的 Xamarin.Forms ListView OutOfMemoryError 异常

标签 c# android image out-of-memory xamarin.forms

有人尝试过使用包含 ImageView 的 ItemTemplate 的 Xamarin.Forms Listview 吗?现在,当 ListView 包含大约 20 行或更多行时会发生什么?

至于我,我有一个大约 4K 大小的 .png 文件加载到 ImageView 中。在应用程序因 OutOfMemoryError 崩溃之前最多显示 9 - 12 行。在 android Manifest 中请求大堆后,应用程序在 60 - 70 行后崩溃。

我知道 Xamarin 提倡使用 BitmapFactory 类来缩小位图,但这不适用于 Xamarin Forms Image View(开箱即用)。

我正在尝试摆弄 ImageRenderer 的子类,看看我是否可以添加 BitmapFactory.Options 属性,以及这是否可以解决问题。

此外,我可能需要检查 Xamarin.Forms 是否在 ViewCell 滚动屏幕后处理(回收)包含的位图。

在开始这段旅程之前,我非常希望收到任何意见,以便让这个过程变得更容易,或者认为这个过程不必要的更简单的解决方案。

期待...

最佳答案

是的,我找到了解决方案。要遵循的代码。但在此之前,让我解释一下我做了什么。

因此,绝对需要自己动手来处理图像及其底层资源(位图或可绘制对象,无论你想如何调用它)。基本上,它归结为处理 native “ImageRenderer”对象。

现在,无法从任何地方获取对该 ImageRenderer 的引用,因为要这样做,需要能够调用 Platform.GetRenderer(...)。无法访问“平台”类,因为它的范围被声明为“内部”。

所以,我别无选择,只能对 Image 类及其 (Android) 渲染器进行子类化,并从内部销毁该渲染器本身(将“true”作为参数传递。不要尝试使用“false” ).在渲染器中,我 Hook 到页面消失(在 TabbedPage 的情况下)。在大多数情况下,Page Disappear 事件不会很好地达到目的,例如当页面仍在屏幕堆栈中但由于另一个页面正在其 Top 上绘制而消失时。如果您处理图像,那么当页面再次被覆盖(显示)时,它将不会显示图像。在这种情况下,我们必须 Hook 主导航页面的“弹出”事件。

我已经尽力解释清楚了。剩下的 - 我希望 - 你能从代码中得到:

这是 PCL 项目中的图像子类。

using System;

using Xamarin.Forms;

namespace ApplicationClient.CustomControls
{
    public class LSImage : Image
    {
    }
}

以下代码在Droid工程中。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Views.InputMethods;
using Android.Widget;
using Android.Util;
using Application.Droid.CustomControls;
using ApplicationClient.CustomControls;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

    [assembly: ExportRenderer(typeof(ApplicationClient.CustomControls.LSImage), typeof(LSImageRenderer))]

    namespace Application.Droid.CustomControls
    {
        public class LSImageRenderer : ImageRenderer
        {
            Page page;
            NavigationPage navigPage;

            protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
            {
                base.OnElementChanged(e);
                if (e.OldElement == null)
                {
                    if (GetContainingViewCell(e.NewElement) != null)
                    {
                        page = GetContainingPage(e.NewElement);
                        if (page.Parent is TabbedPage)
                        {
                            page.Disappearing += PageContainedInTabbedPageDisapearing;
                            return;
                        }

                        navigPage = GetContainingNavigationPage(page);
                        if (navigPage != null)
                            navigPage.Popped += OnPagePopped;
                    }
                    else if ((page = GetContainingTabbedPage(e.NewElement)) != null)
                    {
                        page.Disappearing += PageContainedInTabbedPageDisapearing;
                    }
                }
            }

            void PageContainedInTabbedPageDisapearing (object sender, EventArgs e)
            {
                this.Dispose(true);
                page.Disappearing -= PageContainedInTabbedPageDisapearing;
            }

            protected override void Dispose(bool disposing)
            {
                Log.Info("**** LSImageRenderer *****", "Image got disposed");
                base.Dispose(disposing);
            }

            private void OnPagePopped(object s, NavigationEventArgs e)
            {
                if (e.Page == page)
                {
                    this.Dispose(true);
                    navigPage.Popped -= OnPagePopped;
                }
            }

            private Page GetContainingPage(Xamarin.Forms.Element element)
            {
                Element parentElement = element.ParentView;

                if (typeof(Page).IsAssignableFrom(parentElement.GetType()))
                    return (Page)parentElement;
                else
                    return GetContainingPage(parentElement);
            }

            private ViewCell GetContainingViewCell(Xamarin.Forms.Element element)
            {
                Element parentElement = element.Parent;

                if (parentElement == null)
                    return null;

                if (typeof(ViewCell).IsAssignableFrom(parentElement.GetType()))
                    return (ViewCell)parentElement;
                else
                    return GetContainingViewCell(parentElement);
            }

            private TabbedPage GetContainingTabbedPage(Element element)
            {
                Element parentElement = element.Parent;

                if (parentElement == null)
                    return null;

                if (typeof(TabbedPage).IsAssignableFrom(parentElement.GetType()))
                    return (TabbedPage)parentElement;
                else
                    return GetContainingTabbedPage(parentElement);
            }

            private NavigationPage GetContainingNavigationPage(Element element)
            {
                Element parentElement = element.Parent;

                if (parentElement == null)
                    return null;

                if (typeof(NavigationPage).IsAssignableFrom(parentElement.GetType()))
                    return (NavigationPage)parentElement;
                else
                    return GetContainingNavigationPage(parentElement);
            }
        }
    }

最后,我将命名空间中应用程序的名称更改为 PCL 项目中的“ApplicationClient”和 Droid 项目中的“Application.Droid”。您应该将其更改为您的应用名称。

此外,Renderer 类末尾的几个递归方法,我知道我可以将它组合成一个通用方法。问题是,我会根据需要一次构建一个。所以,这就是我离开的方式。

快乐编码,

阿夫罗霍姆

关于c# - Android 上的 Xamarin.Forms ListView OutOfMemoryError 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25807196/

相关文章:

java - 增强现实中的模式匹配

java - android.view.InflateException : Binary XML file line #29: Error inflating class android. widget.Button

javascript - 帮助调整容器中的图像大小

c# - System.Net.Http.MultipartFormDataContent 的 "curl -F"参数是否等效?

android - 如何在 xamarin.android 中创建新的 keystore ?

C# 字节数组到图像不使用相同的字节数组

image - 45度线的OpenCV线检测

python - 如何使用 Python OpenCV 确定内部轮廓和外部轮廓?

c# - 什么是 Roslyn 中的 PatternSyntax

c# - 如何在 WCF 服务中使用 IDispatchMessageInspector?