Xamarin.Forms Android端非托管代码抛出ConcurrentModificationException异常求解
异常诱因
- 从堆栈信息可以明确异常触发在Telerik
RadScrollView的notifyLaidOutListeners方法中:该方法遍历监听器集合时,集合被其他线程同时修改,触发了ArrayList的并发修改校验。 - 常见触发场景包括:后台线程直接修改RadScrollView的绑定数据源、子元素属性、滚动状态等,刚好和UI线程的布局遍历操作撞在同一时间点;使用的Telerik UI for Xamarin版本过旧,旧版本的RadScrollView未对监听器遍历做并发保护;RadScrollView与Xamarin原生ScrollView嵌套使用,反复触发布局事件导致监听器集合被频繁修改。
解决方案
- 优先升级Telerik UI for Xamarin到2022 Q2及以上的稳定版本,该版本官方已经修复了这个并发问题,修复逻辑为遍历监听器前先生成集合副本,避免原集合修改影响遍历过程。
- 所有涉及RadScrollView的属性修改、子元素增删、数据源更新操作,全部用
Device.BeginInvokeOnMainThread包裹,强制在UI线程执行,杜绝跨线程修改集合的可能。 - 若暂时无法升级Telerik版本,可在Android平台自定义RadScrollView的Renderer,捕获该偶发异常即可,不会影响正常布局逻辑,示例代码如下:
[assembly: ExportRenderer(typeof(Telerik.XamarinForms.Primitives.RadScrollView), typeof(CustomRadScrollViewRenderer))] namespace 你的应用命名空间.Droid.Renderers { public class CustomRadScrollViewRenderer : Telerik.XamarinForms.Primitives.Renderer.Android.ScrollView.RadScrollViewRenderer { public CustomRadScrollViewRenderer(Context context) : base(context) { } protected override void OnLayout(bool changed, int left, int top, int right, int bottom) { try { base.OnLayout(changed, left, top, right, bottom); } catch (Java.Util.ConcurrentModificationException) { // 忽略该偶发异常 } } } }
- 检查页面布局结构,避免RadScrollView与原生ScrollView嵌套使用,统一用RadScrollView作为滚动容器,减少不必要的布局事件触发。
内容的提问来源于stack exchange,提问作者Kikanye
相关产品推荐
相关产品推荐

