0

I'm having issue with growing memory problem. Sometimes after few minutes the app crashes due to out of memory exception. I retrieve the images from SQL server database and it converts from bytes in a separate class.

my XAML view:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TestProject.Views.DetailViews.JsonDesertPage"
             xmlns:local ="clr-namespace:TestProject.Data">
    <ContentPage.Resources>
        <ResourceDictionary>
            <local:ByteArrayToImageConverter x:Key="severityTypeImageConvertertwo"/>
        </ResourceDictionary>
    </ContentPage.Resources>
    <ListView x:Name="listviewConactstwo" RowHeight="100" HorizontalOptions="FillAndExpand" HasUnevenRows="True" ItemSelected="listviewContacts_ItemSelected">
        <ActivityIndicator x:Name="ProgressLoadertwo" IsRunning="True"/>
        <ListView.ItemTemplate >
            <DataTemplate>
                <ViewCell>
                    <StackLayout  Orientation="Vertical" Padding="5">
                        <StackLayout Orientation="Horizontal"  BackgroundColor="Ivory" Opacity="0.9">
                            <Image Source="{Binding Image,Converter={StaticResource severityTypeImageConvertertwo}}" HeightRequest="120" WidthRequest="120"/>
                            <StackLayout Orientation="Vertical">
                                <Label Text="{Binding Name}" FontSize="Medium" TextColor="Gray" FontAttributes="Bold"/>
                                <BoxView HeightRequest="2" Margin="0,10,10,0" BackgroundColor="Gray" HorizontalOptions="FillAndExpand" />
                                <Label Text="{Binding Description}" FontSize="Micro" TextColor="Gray" FontAttributes="Bold"/>
                                <StackLayout Orientation="Horizontal" VerticalOptions="Start" HorizontalOptions="Start">
                                    <Label Text="$" FontSize="Micro" VerticalOptions="Start" HorizontalOptions="Start" TextColor="Gray" FontAttributes="Bold"/>
                                    <Label Text="{Binding Price}" FontSize="Micro" TextColor="Gray" FontAttributes="Bold"/>
                                </StackLayout>
                            </StackLayout>
                            <Image Source="arrowtwo.png" BackgroundColor="Transparent" WidthRequest="25" Margin="0,10,10,0"/>
                        </StackLayout>                        
                    </StackLayout>                    
                </ViewCell>                
            </DataTemplate>            
        </ListView.ItemTemplate>        
    </ListView>
</ContentPage>

my code behind:

using Newtonsoft.Json;
using Plugin.Connectivity;
using System;
using System.IO;
using System.Net.Http;
using TestProject.Data;
using TestProject.Models;
using Xamarin.Forms;

namespace TestProject.Views.DetailViews
{
    public partial class JsonDesertPage : ContentPage
    {
        public JsonDesertPage ()
        {
            InitializeComponent ();   

            this.BackgroundImage = "background.png";
            this.Title = "Soup Menu";
            GetJSON();
          //  CrossConnectivity.Current.ConnectivityChanged += Current_ConnectivityChanged;
        }


        protected async override void OnAppearing()
        {
            base.OnAppearing();

            if (!CrossConnectivity.Current.IsConnected)
            {
                await DisplayAlert("fail", "No Internet Connection.Offline Menu Activated", "Ok");
                await Navigation.PushAsync(new MainTabbed());
            }
            else
            {
                // await DisplayAlert("sucess", " Network Is Available.", "Ok");
                GetJSON();
            }
        }

        public async void GetJSON()
        {                
            var client = new HttpClient();
            // var response = await client.GetAsync("http://192.168.43.226/GetContactsDesert.php");
            var response = await client.GetAsync(Constants.BaseUrlpos + "GetContactsDesert.php");    

            string contactsJson = response.Content.ReadAsStringAsync().Result;   
            ContectList ObjContactList = new ContectList();

            if (response.IsSuccessStatusCode)
            {                    
                ObjContactList = JsonConvert.DeserializeObject<ContectList>(contactsJson);
                listviewConactstwo.ItemsSource = ObjContactList.contacts;
            }

            else
            {
                var textReader = new JsonTextReader(new StringReader(contactsJson));
                dynamic responseJson = new JsonSerializer().Deserialize(textReader);
                contactsJson = "Deserialized JSON error message: " + responseJson.Message;
                await DisplayAlert("fail", "no Network Is Available.", "Ok");
            }

            ProgressLoadertwo.IsVisible = false;            

        }

        private void listviewContacts_ItemSelected(object sender, SelectedItemChangedEventArgs e)
        {
            var itemSelectedData = e.SelectedItem as Contactone;
            Navigation.PushAsync(new JsonDetailsPage(itemSelectedData.ID, itemSelectedData.Image, itemSelectedData.Name, itemSelectedData.Code, itemSelectedData.Description, itemSelectedData.Price,itemSelectedData.isservicecharge, itemSelectedData.CostPrice));

        }
    }
}

This is one of the pages i am using:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace TestProject.Data
{
    public class ByteArrayToImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            ImageSource retSource = null;
            if (value != null)
            {
                byte[] imageAsBytes = (byte[])value;
                // byte[] decodedByteArray = System.Convert.FromBase64String(Encoding.UTF8.GetString(imageAsBytes, 0, imageAsBytes.Length));
                // var stream = new MemoryStream(decodedByteArray);
                retSource = ImageSource.FromStream(() => new MemoryStream(imageAsBytes));
            }
            return retSource;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            //return null;
            throw new NotImplementedException();
        }

    }
}

when i ran the profile i can see the bye[ ] is growing up as i move among pages. i tried the FFimageloading option and it doesn't seem to support the byte array image converters.

How to get rid of the memory growing issue?

James Z
  • 12,209
  • 10
  • 24
  • 44
pan
  • 53
  • 8

1 Answers1

0

Spotted a few things. Without a full run I can't determine which are your headaches but...

Use HttpClient as a singleton. I've confirmed with a Xam arch the singleton usage is optimal for Xam as well as everything else.

Watch out for IDiposable objects.

The following code returns an HttpResponse method. HttpResponseMessage is IDisposeable. Wrap it in a "using".

StringReader inherits from TextReader, which is IDisposable. Wrap in "using".

Dynamic type is indeterminate. Best to wrap it in a using as well. See Do you need to dispose of objects and set them to null? for more info.

PNP Guide to HttpClient - https://github.com/mspnp/performance-optimization/blob/465514674354c8f833c73882f7405ac22c4fd437/ImproperInstantiation/docs/ImproperInstantiation.md

PNP Good/Bad HttpClient Sample - https://github.com/mspnp/performance-optimization/tree/465514674354c8f833c73882f7405ac22c4fd437/ImproperInstantiation

You're using HttpClient wrong and it is destabilizing your software - http://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

See if this helps.

    private HttpClient m_httpClient = new HttpClient();
    private HttpClient MyHttpClient
    {
        get
        {
            if ( m_httpClient==null )
            {
                m_httpClient = new HttpClient();
            }
            return m_httpClient;
        }
    }
    public async void GetJSON()
    {
        // var client = new HttpClient();
        var client = MyHttpClient;

        // var response = await client.GetAsync("http://192.168.43.226/GetContactsDesert.php");
        // var response = await client.GetAsync(Constants.BaseUrlpos + "GetContactsDesert.php");
        string contactsJson = string.Empty;
        using (HttpResponseMessage response = await client.GetAsync(Constants.BaseUrlpos + "GetContactsDesert.php"))
        { 
            contactsJson = response.Content.ReadAsStringAsync().Result;
        }
        ContectList ObjContactList = new ContectList();

        if (response.IsSuccessStatusCode)
        {
            ObjContactList = JsonConvert.DeserializeObject<ContectList>(contactsJson);
            listviewConactstwo.ItemsSource = ObjContactList.contacts;
        }

        else
        {
            using (var textReader = new JsonTextReader(new StringReader(contactsJson)) )
            {
                using (dynamic responseJson = new JsonSerializer().Deserialize(textReader))
                { 
                    contactsJson = "Deserialized JSON error message: " + responseJson.Message;
                }
                await DisplayAlert("fail", "no Network Is Available.", "Ok");
            }
        }

        ProgressLoadertwo.IsVisible = false;
    }
Joe Healy
  • 5,769
  • 3
  • 38
  • 56
  • Thank you so much fro the answer, but there is an error shows in the "if (response.IsSuccessStatusCode)" , and i tried to correct it but not possible, i can show you the xamarin profiler images if you like the rate the stack grw as the images load in to the listview. as far as i understand the reason the stack increase in the loaded images are not disposing . if there is a way to dispose the listview images when i navigate to the next page , that might help to get rid of keeping the preloaded images, problem is i dont know how to do it???? – pan Nov 20 '17 at 18:21
  • Post a simple reproduction I can run to a GitHub and i'll take a look. – Joe Healy Nov 20 '17 at 19:11
  • I m quit New to github so i have uploaded my project files , if you are unable to get it let me know to change in github the link https://github.com/wpanduka/panPosSystem – pan Nov 21 '17 at 06:12
  • Hi Joe, Did you have time to have a look at the GitHub files i uploaded ? please let me know , thank you so much. – pan Nov 22 '17 at 05:06