Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xamarin.Forms Grouped List View fails on adding new groups in Android

I am using Xamarin.Forms for developing mobile apps for Android and windows Phone.

I have a listview of messages which is bound to an ObservableCollection of groups. The list groups the messages by day then the messages show in order of the time - pretty standard stuff.

The problem I have now encountered is that in Android - using the Add function to add new groups to the ObservableCollection causes an unhandled exception to fire.

04-22 13:13:32.404 D/Mono (19971): DllImport attempting to load: '/system/lib/liblog.so'. 04-22 13:13:32.404 D/Mono (19971): DllImport loaded library '/system/lib/liblog.so'. 04-22 13:13:32.404 D/Mono (19971): DllImport searching in: '/system/lib/liblog.so' ('/system/lib/liblog.so'). 04-22 13:13:32.404 D/Mono (19971): Searching for '__android_log_print'. 04-22 13:13:32.414 D/Mono
(19971): Probing '__android_log_print'. 04-22 13:13:32.414 D/Mono
(19971): Found as '__android_log_print'. 04-22 13:13:32.434 I/MonoDroid(19971): UNHANDLED EXCEPTION: An unhandled exception occured.

04-22 13:13:32.444 I/MonoDroid(19971): System.ArgumentOutOfRangeException: Argument is out of range. 04-22 13:13:32.444 I/MonoDroid(19971): Parameter name: index 04-22 13:13:32.444 I/MonoDroid(19971): at System.Collections.Generic.List1<object>.get_Item (int) <0x0007c> 04-22 13:13:32.444 I/MonoDroid(19971): at Cadenza.Collections.OrderedDictionary2, Xamarin.Forms.Cell>>.get_Item (int) <0x00063>

This is not a problem in Windows.

I can get around this by using the AddRange function and simply adding the item I want to add to another "temporary list" first, then add that temporary list to the main Collection - This gets around it but seems a bit of a hack.

Another way would be to do this on the main thread:

Device.BeginInvokeOnMainThread(() =>
{
   // using of add function in this manner works.
});

Has anyone had a similar problem and have you found a solution to it?

Thanks,

like image 207
TResponse Avatar asked Apr 22 '15 01:04

TResponse


Video Answer


2 Answers

You're doing Add operations from a different threads. ObservableCollection is not thread safe.

  • You could fix that by creating a custom thread safe ObservableCollection (eg. simplest one using lock statements or even Device.BeginInvokeOnMainThread calls which will queue operations on a main thread).

  • You could also use BindingBase.EnableCollectionSynchronization for a collections synchronization. https://forums.xamarin.com/discussion/19114/invalid-number-of-rows-in-section

like image 83
Daniel Luberda Avatar answered Sep 24 '22 23:09

Daniel Luberda


Building on @Daniel Luberda's answer, I too recommend using BindingBase.EnableCollectionSynchronization, because ObservableCollection is not thread safe.

I put together a blog post on the topic here: https://www.codetraveler.io/2019/08/27/using-observablecollection-in-a-multi-threaded-xamarin-forms-application/

BindingBase.EnableCollectionSynchronization Example

Note: Ensure that you initialize the ObservableCollection before calling EnableCollectionSynchronization

class MyViewModel
{
    public MyViewModel()
    {
        MyCollection = new ObservableCollection<MyModel>();
        Xamarin.Forms.BindingBase.EnableCollectionSynchronization(MyCollection, null, ObservableCollectionCallback);
    }

    public ObservableCollection<MyModel> MyCollection { get; }

    void ObservableCollectionCallback(IEnumerable collection, object context, Action accessMethod, bool writeAccess)
    {
        lock (collection)
        {
            accessMethod?.Invoke();
        }
    }
}
like image 40
Brandon Minnick Avatar answered Sep 25 '22 23:09

Brandon Minnick