Xamarin.Forms的ListView OutOfMemeoryError在Android [英] Xamarin.Forms ListView OutOfMemeoryError on Android

查看:451
本文介绍了Xamarin.Forms的ListView OutOfMemeoryError在Android的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有谁试过Xamarin.Forms列表视图包含一个图像视图一个ItemTemplate?现在,当ListView控件包含CA 20个或更多的行会发生什么?

Anyone ever tried A Xamarin.Forms Listview with an ItemTemplate containing a Image view? Now, what happens when ListView contains ca 20 or more rows?

至于我,我有4K左右的大小装入图像视图.png文件。得到了最高的9 - 12上映之前,应用程序崩溃与OutOfMemoryError而行。要求一大堆的Andr​​oid清单后,60后,应用程序崩溃 - 70行。

As for me, I have a .png file of around 4K in size loaded into the Image view. Got a maximum of 9 - 12 rows shown before application crashed with a OutOfMemoryError. After requesting a large heap in the android Manifest, the app crashes after 60 - 70 rows.

我知道Xamarin正在推广使用的BitmapFactory类缩减位图的,但是这是不适用(开箱)为Xamarin窗体图像视图。

I know that Xamarin is promoting the use of the BitmapFactory class to scale down bitmaps, but this is not applicable (out of the box) for the Xamarin Forms Image View.

我正要试图拨弄ImageRenderer的子类,看看我是否可以添加BitmapFactory.Options财产,这是否会解决这个问题。

I'm about trying to fiddle with a Sub Class of the ImageRenderer to see if I can add a BitmapFactory.Options property and if this will solve the problem.

另外,我可能需要检查是否Xamarin.Forms并处置(回收)所包含的位图后ViewCell正在滚动的画面。

Also, I might need to check out if Xamarin.Forms does dispose (recycle) the contained bitmap after the ViewCell is being scrolled of the screen.

在这个旅程的时候,我会非常渴望得到任何意见,可以使这更容易或更简单的解决方案,认为这一过程是不必要的。

Before setting out on this journey, I would be very keen to get any comments that could make this easier or a simpler solution that would deem this process unnecessary.

期待......

推荐答案

是的,我找到了解决办法。 code效仿。但在此之前,让我解释一下我做了什么。

Yes, I found a solution. Code to follow. But before that, let me explain a bit what I have done.

因此​​,有绝对需要采取的事宜中在我们自己手中处置的形象和基础资源(位图或绘制,但是你怎么称呼它)。基本上,它归结为处理本机ImageRenderer对象。

So, there's definitely a need to take maters in our own hands to dispose the image and its underlying resources (bitmap or drawable, however you want to call it). Basically, it comes down to dispose the native 'ImageRenderer' object.

现在,没有办法来获得参考从任何地方ImageRenderer因为为了这样做,人们需要能够调用Platform.GetRenderer(...)。访问'平台'类是不可访问,因为它的范围被声明为内部。

Now, there's no way to obtain a reference to that ImageRenderer from anywhere because in order to do so, one need to be able to call Platform.GetRenderer(...). Access to the 'Platform' class is inaccessible since its scope is declared as 'internal'.

所以,我已经别无选择,而不是子类的其他图像类和它(机器人)渲染和销毁该渲染器本身从内(传递'真'的说法。不要试图与假 )。里面的渲染我勾上页消失(如果发生TabbedPage的)。在大多数情况下,页面消失事件将不会达到目的还有,比如当页面仍然在屏幕堆栈,但消失,由于被画在热门它的另一页。如果你处理的图像(S)比,当页面被发现(图)再次,它不会显示图像。在这种情况下,我们要勾上主要的导航页的弹出事件。

So, I have been left with no choice other than to sub-class the Image class and its (Android) Renderer and destroy this Renderer itself from inside (passing 'true' as argument. Don't try with 'false'). Inside the Renderer I hook on to page disappear (In case of a TabbedPage). In most situations the Page Disappear event will not serve the purpose well, such as when the page is still in the screen stack but disappears due to a another page is being drawn on Top of it. If you dispose the Image(s) than, when the page gets uncovered (shown) again, it will not display the images. In such case we have to hook on the the main Navigation Page's 'Popped' event.

我试图解释尽我所能。其余的 - 我希望 - 你将能够从code获得:

I have tried to explain to the best I could. The rest - I hope - you will be able to get from the code:

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

This is the Image Sub-Class in the PCL Project.

using System;

using Xamarin.Forms;

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

下面code是在Droid的项目。

The following code is in the Droid project.

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

最后,我已经改变了应用程序的名称命名空间为'ApplicationClient在PCL项目和Droid的项目为Application.Droid。你应该将其更改为你的应用程序名称。

Finally, I have changed the Name of the Application in the namespace to 'ApplicationClient' in the PCL project and to 'Application.Droid' in Droid project. You should change it to your app name.

此外,一些递归方法在渲染器类的末尾,我知道我可以合并成一个通用的方法。问题是,我有建一次在需要的时候。所以,这就是我离开它。

Also, the few recursive methods at the end of the Renderer class, I know that I could combine it into one Generic method. The thing is, that I have build one at a time as the need arose. So, this is how I left it.

快乐编码,

Avrohom

这篇关于Xamarin.Forms的ListView OutOfMemeoryError在Android的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆