Xamarin.Forms memory leak handling

I have a memory leak problem in my application that I created using Xamarin.Forms. My application consists of A ListView with images. If I click on an item and return to ListPage, I will see a pop-up memory window in the "Exit" window. I tried calling GC.Collect() in OnDisappearing() my ContentPage.

I saw base.Dispose() in my Android project. But I do not know how to use it.

ArticleListPage.xaml

 <?xml version="1.0" encoding="utf-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:converters="clr-namespace:NewsArticles.Mobile.Converters;assembly=Something.NewsArticles.Mobile" xmlns:themes="clr-namespace:NewsArticles.Mobile.Themes;assembly=Something.NewsArticles.Mobile" x:Class="NewsArticles.Mobile.Pages.ArticlesListPage" Title="{Binding PageTitle, Mode=OneWay}" BackgroundColor="{x:Static themes:ColorResources.ArticleListPageBackgroundColor}"> <RelativeLayout> <ContentPage.Resources> <ResourceDictionary> <converters:BooleanNegationConverter x:Key="booleanNegationConverter" /> <converters:StringToImageSourceConverter x:Key="stringToImageSourceConverter" /> </ResourceDictionary> </ContentPage.Resources> <ListView x:Name="ArticlesList" StyleId="ArticlesList" Grid.Row="1" IsVisible="{Binding IsProcessing, Mode=OneWay, Converter={StaticResource booleanNegationConverter}}"> <ListView.BackgroundColor> <OnPlatform x:TypeArguments="Color" iOS="Transparent" /> </ListView.BackgroundColor> <ListView.RowHeight> <OnPlatform x:TypeArguments="x:Int32" iOS="150" Android="180" WinPhone="170" /> </ListView.RowHeight> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <ContentView BackgroundColor="{x:Static themes:ColorResources.ArticleListViewBackgroundColor}"> <ContentView.Padding> <OnPlatform x:TypeArguments="Thickness" iOS="10,5" Android="10,10" WinPhone="10,10" /> </ContentView.Padding> <Grid BackgroundColor="White" Padding="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="120"/> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Image Grid.Column="0" Source="{Binding ImageUrl, Mode=OneWay, Converter={StaticResource stringToImageSourceConverter}}" HorizontalOptions="FillAndExpand" Aspect="AspectFill" /> <Grid Grid.Column="1" RowSpacing="0"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="20" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Label Grid.Row="0" Text="{Binding Title, Mode=OneWay}" VerticalOptions="Start" LineBreakMode="WordWrap" TextColor="{x:Static themes:ColorResources.MainArticleTitleColor}" Font="{x:Static themes:FontResources.ListArticleTitle}" /> <ContentView Grid.Row="1" Padding="0,2"> <Label Text="{Binding Author, Mode=OneWay }" TextColor="Silver" Font="{x:Static themes:FontResources.VerySmall}" /> </ContentView> <Label Grid.Row="2" Text="{Binding Body, Mode=OneWay}" LineBreakMode="TailTruncation" TextColor="Gray" Font="{x:Static themes:FontResources.VerySmall}" /> </Grid> </Grid> </ContentView> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </ContentPage> 
+4
source share
1 answer

I had this problem a while ago, and this article resolved this for me. Basically you need to create your own renderer and put it 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); } } } 

Then extend the Image class and place it in the PCL or wherever your pages are.

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

Then you need to change the XAML to work with this.

 <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:ctrls="clr-namespace:ApplicationClient.CustomControls;assembly=ApplicationClient" ... > <ctrls:LSImage ... /> </ContentPage> 
+5
source

Source: https://habr.com/ru/post/1265597/


All Articles