Hello,
When releasing my app in some Lollipop Devices I got some issues with OutOfMemoryError.
The error always happen in ListViews with images. In this case also CircleImages.
The error is:
java.lang.OutOfMemoryError: Failed to allocate a 18662412 byte allocation with 1643192 free bytes and 1604KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:741)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:562)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:590)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:620)
I have already research and tried a lot of solution but none succeed.
Solutions that I tried so far:
1 - From this topic, I tried to call GC.Collector(1) always when an image is compiled. I add a custom renderer like this:
[assembly: ExportRenderer(typeof(Image), typeof(ImageFixRenderer))]
public class ImageFixRenderer : ImageRenderer
{
public ImageFixRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
GC.Collect(1);
}
protected override void Dispose (bool disposing)
{
try
{
base.Dispose(disposing);
GC.Collect(1);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString ());
}
}
}
But it did not worked.
2 - From this topic , I tried to increase my Java Max Heap Size in Android Options, Advanced Tab to 1G.
But it did not worked also.
3 - From this topic, I tried to add android:largeHeap="true" in manifest file.
But not worked too.
Here is my custom CircleImageRender:
public class CircleImageRenderer : ImageFixRenderer
{
/// <summary>
/// Used for registration with dependency service
/// </summary>
public static void Init() { }
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
//GC.Collect(1);
if (e.OldElement == null)
{
//Only enable hardware accelleration on lollipop
if ((int)Android.OS.Build.VERSION.SdkInt < 21)
{
SetLayerType(LayerType.Software, null);
}
}
}
/// <summary>
///
/// </summary>
/// <param name="canvas"></param>
/// <param name="child"></param>
/// <param name="drawingTime"></param>
/// <returns></returns>
protected override bool DrawChild(Canvas canvas, global::Android.Views.View child, long drawingTime)
{
try
{
var radius = Math.Min(Width, Height) / 2;
var strokeWidth = 10;
radius -= strokeWidth / 2;
Path path = new Path();
path.AddCircle(Width / 2, Height / 2, radius, Path.Direction.Ccw);
canvas.Save();
canvas.ClipPath(path);
var result = base.DrawChild(canvas, child, drawingTime);
canvas.Restore();
path = new Path();
path.AddCircle(Width / 2, Height / 2, radius, Path.Direction.Ccw);
var paint = new Paint();
paint.AntiAlias = true;
paint.StrokeWidth = ((CircleImage)Element).BorderThickness;
paint.SetStyle(Paint.Style.Stroke);
paint.Color = ((CircleImage)Element).BorderColor.ToAndroid();
canvas.DrawPath(path, paint);
paint.Dispose();
path.Dispose();
return result;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Unable to create circle image: " + ex);
}
return base.DrawChild(canvas, child, drawingTime);
}
}
Please I really need help on this. Anyone can give a hint?