0

I am working on a Xamarin.Forms Android Project that displays images one after another on a press of a button. My current test device is an HTC Nexus 9 and apparently, due to its limited specs, i get below error when trying to load my 17th image:

java.lang.OutOfMemoryError: Failed to allocate a 11059212 byte allocation with 8286168 free bytes and 7MB until OOM
    at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:620)
    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:455)
    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:1155)
    at android.content.res.ResourcesImpl.loadDrawableForCookie(ResourcesImpl.java:720)
    at android.content.res.ResourcesImpl.loadDrawable(ResourcesImpl.java:571)
    at android.content.res.Resources.getDrawable(Resources.java:771)
    at android.content.Context.getDrawable(Context.java:525)
    at androidx.core.content.ContextCompat.getDrawable(ContextCompat.java:455)
    at androidx.appcompat.widget.ResourceManagerInternal.getDrawable(ResourceManagerInternal.java:144)
    at androidx.appcompat.widget.ResourceManagerInternal.getDrawable(ResourceManagerInternal.java:132)
    at androidx.appcompat.content.res.AppCompatResources.getDrawable(AppCompatResources.java:104)
    at crc64ee486da937c010f4.ButtonRenderer.n_onClick(Native Method)
    at crc64ee486da937c010f4.ButtonRenderer.onClick(ButtonRenderer.java:104)
    at android.view.View.performClick(View.java:5637)
    at android.view.View$PerformClick.run(View.java:22433)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6229)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:891)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:781)

I tried setting the Java Max Heap Size to 1G under .Android > Properties > Android Options > Advanced but nothing changed. enter image description here

I found a potential solution here but apparently, its for Java based Android App and i don't know where to find a similar manifest file on Xamarin.Forms` Android Project.

Below is a snippet of my code using the simplest MVVM implementation:

.xaml

<Image Source="{Binding ImgSource}"
       WidthRequest="960"
       HeightRequest="720" />
       

<!--#region Page1 Controls-->
<Button Command="{Binding Page1DhcpIconCommand}"
        IsVisible="{Binding Page1ControlVisible}"
        BackgroundColor="{Binding Page1ControlColor}"
        Opacity="0.25"
        RelativeLayout.XConstraint="57"
        RelativeLayout.YConstraint="679"
        RelativeLayout.WidthConstraint="46"
        RelativeLayout.HeightConstraint="37" />
<!--#endregion-->

<!--#region Page2 Controls-->
<Button Command="{Binding Page2RolesCommand}"
        IsVisible="{Binding Page2ControlVisible}"
        BackgroundColor="{Binding Page2ControlColor}"
        Opacity="0.25"
        RelativeLayout.XConstraint="24"
        RelativeLayout.YConstraint="85"
        RelativeLayout.WidthConstraint="46"
        RelativeLayout.HeightConstraint="15" />
<!--#endregion-->

<!--#region Page3 Controls-->
<Button Command="{Binding Page3AddRolesCommand}"
        IsVisible="{Binding Page3ControlVisible}"
        BackgroundColor="{Binding Page3ControlColor}"
        Opacity="0.25"
        RelativeLayout.XConstraint="720"
        RelativeLayout.YConstraint="199"
        RelativeLayout.WidthConstraint="71"
        RelativeLayout.HeightConstraint="21" />
<!--#endregion-->

ViewModel.cs

#region Backing Fields
string imgSource;

bool page1ControlVisible;
string page1ControlColor;

bool page2ControlVisible;
string page2ControlColor;

bool page3ControlVisible;
string page3ControlColor;
#endregion
#region Private Variables
private readonly bool _transparentOverride;
#endregion
#region Public Properties
public string ImgSource
{
    get => imgSource;
    set => SetProperty(ref imgSource, value);
}

#region Page1 Properties & Commands
public bool Page1ControlVisible
{
    get => page1ControlVisible;
    set => SetProperty(ref page1ControlVisible, value);
}
public string Page1ControlColor
{
    get => page1ControlColor;
    set => SetProperty(ref page1ControlColor, value);
}

public Command Page1DhcpIconCommand { get; }
#endregion

#region Page2 Properties & Commands
public bool Page2ControlVisible
{
    get => page2ControlVisible;
    set => SetProperty(ref page2ControlVisible, value);
}
public string Page2ControlColor
{
    get => page2ControlColor;
    set => SetProperty(ref page2ControlColor, value);
}

public Command Page2RolesCommand { get; }
#endregion

#region Page3 Properties & Commands
public bool Page3ControlVisible
{
    get => page3ControlVisible;
    set => SetProperty(ref page3ControlVisible, value);
}
public string Page3ControlColor
{
    get => page3ControlColor;
    set => SetProperty(ref page3ControlColor, value);
}

public Command Page3AddRolesCommand { get; }
#endregion
#endregion


public DHCPConfigurationViewModel()
{
    _transparentOverride = true;

    ImgSource = "img_dhcp_config_01.jpg";

    #region Page1 Properties & Commands
    Page1ControlVisible = true;
    Page1ControlColor = _transparentOverride ? "Transparent" : "Red";

    Page1DhcpIconCommand = new Command(Page1DhcpIcon);
    #endregion

    #region Page2 Properties & Commands
    Page2ControlVisible = false;
    Page2ControlColor = _transparentOverride ? "Transparent" : "Orange";

    Page2RolesCommand = new Command(Page2Roles);
    #endregion

    #region Page3 Properties & Commands
    Page3ControlVisible = false;
    Page3ControlColor = _transparentOverride ? "Transparent" : "Yellow";

    Page3AddRolesCommand = new Command(Page3AddRoles);
    #endregion
}

private void Page1DhcpIcon()
{
    ImgSource = "img_dhcp_config_02.jpg";

    Page1ControlVisible = false;
    Page2ControlVisible = true;
}

private void Page2Roles()
{
    ImgSource = "img_dhcp_config_03.jpg";

    Page2ControlVisible = false;
    Page3ControlVisible = true;
}

private void Page3AddRoles()
{
    ImgSource = "img_dhcp_config_04.jpg";

    Page3ControlVisible = false;
    Page4ControlVisible = true;
}
Nii
  • 450
  • 6
  • 25

1 Answers1

0

For this, you can check document Improve Xamarin.Forms App Performance.

Specially part: Optimize image resources:

Displaying image resources can greatly increase an application's memory footprint. Therefore, they should only be created when required and should be released as soon as the application no longer requires them. For example, if an application is displaying an image by reading its data from a stream, ensure that stream is created only when it's required, and ensure that the stream is released when it's no longer required. This can be achieved by creating the stream when the page is created, or when the Page.Appearing event fires, and then disposing of the stream when the Page.Disappearing event fires.

When downloading an image for display with the ImageSource.FromUri method, cache the downloaded image by ensuring that the UriImageSource.CachingEnabled property is set to true.

You can also try nuget Xamarin.FFImageLoading.Forms,which is a xamarin Library to load images quickly and easily on Xamarin.Forms. For more details,please check:https://github.com/luberda-molinet/FFImageLoading .

Jessie Zhang -MSFT
  • 9,830
  • 1
  • 7
  • 19
  • Hi, as i understand it. Xamarin.FFImageLoading.Forms and the Documentation caters to images sourced from a `Uri`. However, my images are local resources stored on the `.Android > Resources > Drawable` folder. I'd like to give the Image from stream a try, but how can this be achieved (and disposed once no longer needed) via MVVM Pattern? – Nii Apr 27 '21 at 11:48
  • Nuget `Xamarin.FFImageLoading.Forms` could also been used for local resources. You can also check the sample code here:https://github.com/luberda-molinet/FFImageLoading/tree/master/samples . – Jessie Zhang -MSFT Apr 27 '21 at 12:01