Xamarin应用INotifyPropertyChanged重新订阅失效仅首次生效问题
Xamarin蓝牙重连后事件订阅失效解决方案
- 优先确认实例一致性
每次重连前后分别打印ble.Adapter、ble、data三个对象的哈希值(调用GetHashCode()方法),对比首次启动和重连后的哈希值:如果不一致,说明你的重连逻辑中生成了新的实例,你现有代码中的-=操作是在旧实例上执行,新实例根本没有绑定对应的事件处理方法,自然不会触发回调。 - 调整订阅逻辑执行时机
不要将订阅逻辑放在if (ble.GetConnectionStatus())的连接成功判断分支内,把订阅逻辑提前到初始化ble适配器、初始化data对象之后,执行蓝牙连接操作之前,避免连接成功后才订阅漏掉中间事件,也避免实例更新后没有同步绑定订阅。 - 优化订阅清理逻辑
新增全局变量保存上一次绑定的实例引用,每次更换实例、重新订阅前先清理旧实例的订阅,避免旧订阅残留,示例代码:// 全局变量保存上次绑定的实例引用 private IAdapter _oldAdapter; private IBle _oldBle; private IData _oldData; // 订阅前先清理旧实例 if (_oldAdapter != null) { _oldAdapter.DeviceConnectionLost -= Adapter_DeviceConnectionLost; } if (_oldBle != null) { _oldBle.PropertyChanged -= Ble_PropertyChanged; } if (_oldData != null) { _oldData.PropertyChanged -= data_PropertyChanged; } // 给当前实例绑定订阅 ble.Adapter.DeviceConnectionLost += Adapter_DeviceConnectionLost; ble.PropertyChanged += Ble_PropertyChanged; data.PropertyChanged += data_PropertyChanged; // 更新保存的实例引用 _oldAdapter = ble.Adapter; _oldBle = ble; _oldData = data; - 保证线程一致性
现有代码中用Device.BeginInvokeOnMainThread切换到主线程操作订阅是正确的,要确保所有订阅、取消订阅操作都在同一个线程执行,如果有后台线程操作事件订阅的场景,也会出现订阅静默失效的问题。 - 改用弱事件模式规避引用残留
如果上述方案都无效,可以改用Xamarin官方提供的WeakEventManager弱事件管理器来订阅事件,避免事件订阅持有实例引用导致旧实例无法释放,也能彻底解决订阅残留导致的失效问题,示例写法:// 订阅事件 WeakEventManager<IAdapter, EventArgs>.AddHandler( ble.Adapter, nameof(ble.Adapter.DeviceConnectionLost), Adapter_DeviceConnectionLost); // 取消订阅事件 WeakEventManager<IAdapter, EventArgs>.RemoveHandler( ble.Adapter, nameof(ble.Adapter.DeviceConnectionLost), Adapter_DeviceConnectionLost);
内容的提问来源于stack exchange,提问作者nszmmp
相关产品推荐
相关产品推荐

