Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xamarin Forms ListView CachingStrategy

I have recently tested the CachingStrategy for a ListView in a Xamarin Forms App with 1000 items in the list. List items are being created from a data template of ViewCell. I Tried using RecycleElement option for CachingStrategy.

When I did profiling, using Xamarin Profiler, for Android App deployed on Xamarin Anroid Player (emulator) I noticed that when I scroll through the list the memory allocation doesn't increase (on allocations summary tab). But, when I did profiling for iPhone App on emulator, I noticed that no data is being displayed on Allocations Summary tab. So I captured some snapshots while scrolling through the list and noticed whenever I scroll through the list (up or down), the memory allocation keeps increasing.

Why RecycleElement is not working for iOS (iPhone)?

I am using Mac for development. Here are my tools:

=== Xamarin Studio ===

Version 5.10.1 (build 3) Installation UUID: 7ae992a3-b710-4297-ba1d-0c519fbb2ea8 Runtime: Mono 4.2.1 (explicit/6dd2d0d) GTK+ 2.24.23 (Raleigh theme)

Package version: 402010102

=== Xamarin.Profiler ===

Version: 0.24.0.0 Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler

=== Apple Developer Tools ===

Xcode 7.1.1 (9081) Build 7B1005

=== Xamarin.iOS ===

Version: 9.2.1.54 (Enterprise Edition) Hash: eb4c1ef Branch: master Build date: 2015-12-01 02:12:30-0500

=== Xamarin.Android ===

Version: 6.0.0.34 (Enterprise Edition) Android SDK: /Users/haider/Library/Developer/Xamarin/android-sdk-macosx Supported Android versions: 4.0.3 (API level 15) 4.4 (API level 19) 5.0 (API level 21) 5.1 (API level 22) 6.0 (API level 23)

SDK Tools Version: 24.4.1 SDK Platform Tools Version: 23.1 rc1 SDK Build Tools Version: 23.0.2

Java SDK: /usr java version "1.7.0_71" Java(TM) SE Runtime Environment (build 1.7.0_71-b14) Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)

=== Xamarin Android Player ===

Version: 0.6.5 Location: /Applications/Xamarin Android Player.app

=== Xamarin.Mac ===

Version: 2.4.0.109 (Starter Edition)

=== Build Information ===

Release ID: 510010003 Git revision: f2021a209d66d49cbc0649a6d968b29040e57807 Build date: 2015-12-01 10:43:40-05 Xamarin addins: dfd4f5103e8951edbc8ac24480b53b53c55e04ff Build lane: monodevelop-lion-cycle6-baseline

=== Operating System ===

Mac OS X 10.11.1 Darwin Haiders-MacBook-Pro.local 15.0.0 Darwin Kernel Version 15.0.0 Sat Sep 19 15:53:46 PDT 2015 root:xnu-3247.10.11~1/RELEASE_X86_64 x86_64

like image 698
Haider Avatar asked Dec 13 '15 08:12

Haider


1 Answers

Here's A Few Things To Check

  1. In the Xamarin Profiler, ensure that you are only looking for the custom ViewCell class, and take multiple snapshots to trigger the garbage collector. It may be something else that is causing the memory leak if the number of ViewCells is not increasing. If the number of ViewCells is increasing, move on to suggestions 2 & 3, below. Xamarin Profiler ViewCell example

  2. In the ViewCell code, make sure to override OnBindingContextChanged() and set the controls' properties in OnBindingContextChanged(), rather than in the ViewCell's constructor. I added some sample code below that shows how to implement the ListViewCachingStrategy.RecycleElement strategy using a custom ViewCell.

  3. If you are subscribing an Event Handler for the ViewCell (to add a Context Action for example), make sure to subscribe the Event Handler in the OnAppearing() method of the ViewCell class and unsubscribe the Event Handler in the OnDisappearing() method of the ViewCell class. I've included a comment in the example ViewCell code below.

ListView Using RecycleElement

ListView = new ListView(ListViewCachingStrategy.RecycleElement)
{
    DataTemplate(typeof(CustomViewCell))
};

ViewCell

public class CustomViewCell : ViewCell
{
    Label _myLabel;
    MenuItem _deleteAction;

    public CustomViewCell()
    {
        _myLabel = new Label();

        View = _myLabel;
    }

    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();

        _myLabel.Text = "";

        var item = BindingContext as MyModel;
        if (item != null)
        {
            _myLabel.Text = item.Text;
        }
    }

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

        //Subscribe ViewCell Event Handlers
        _deleteAction.Clicked += HandleDeleteClicked;
        ContextActions.Add(_deleteAction);
    }

    protected override void OnDisappearing()
    {
        base.OnDisappearing();

        //Unsubscribe ViewCell Event Handlers
        _deleteAction.Clicked -= HandleDeleteClicked;
        ContextActions.Remove(_deleteAction);
    }

    void HandleDeleteClicked(object sender, EventArgs e)
    {
        //Code to handle when the delete action is tapped
    }
}

ViewCell Model

public class MyModel
{
    [PrimaryKey]
    public int ID { get; set; }

    public string Text { get; set; }
}
like image 176
Brandon Minnick Avatar answered Oct 05 '22 23:10

Brandon Minnick