Xamarin.Forms 分组列表视图无法在 Android 中添加新组

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

我正在使用 Xamarin.Forms 为 Android 和 windows Phone.

开发移动应用程序

我有一个消息列表视图,它绑定到组的 ObservableCollection。该列表按天对消息进行分组,然后按时间顺序显示消息 - 非常标准的东西。

我现在遇到的问题是,在 Android 中 - 使用 Add 函数将新组添加到 ObservableCollection 会导致触发未处理的异常。

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>

这在 Windows 中不是问题。

我可以通过使用 AddRange 函数来解决这个问题,只需先将我要添加的项目添加到另一个 "temporary list",然后将该临时列表添加到main Collection - 这解决了它,但似乎有点 hack。

另一种方法是在主线程上执行此操作:

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

有没有人遇到过类似的问题,你找到解决办法了吗?

谢谢,

您正在从不同的线程执行 Add 操作。 ObservableCollection 不是线程安全的。

  • 您可以通过创建自定义线程安全 ObservableCollection 来解决这个问题(例如,最简单的使用 lock 语句甚至 Device.BeginInvokeOnMainThread 调用,它将对操作进行排队一个主线程)。

  • 您也可以使用 BindingBase.EnableCollectionSynchronization 进行集合同步。 https://forums.xamarin.com/discussion/19114/invalid-number-of-rows-in-section

基于 @Daniel Luberda's , I too recommend using BindingBase.EnableCollectionSynchronization,因为 ObservableCollection 不是线程安全的。

我在这里整理了一篇关于该主题的博客 post:https://www.codetraveler.io/2019/08/27/using-observablecollection-in-a-multi-threaded-xamarin-forms-application/

BindingBase.EnableCollectionSynchronization 例子

注意:确保在调用 EnableCollectionSynchronization

之前初始化 ObservableCollection
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();
        }
    }
}
            Task loadLineItems = Task.Run( () =>
            {
                foreach (listEntity item in newList)
                {
                    this.ObservalCollectionFromVM.Add(item);
                }
            });
            loadLineItems.Wait();

            Task loadLineItems = Task.Run(async () =>
            {
                var list == await DependencyService.Get<IEntityService>().GetEntityListAsync();
                foreach (Entity item in list)
                {
                    this.ObservalCollectionFromVM.Add(item);
                }
            });
            loadLineItems.Wait();