在Xamarin.Forms中使用Rx.Net:OnNext事件未触发问题排查
问题:Rx.Net OnNext事件未触发的排查与解决方法
问题场景
希望将Rx.Net的Subject封装在独立的RxNetHandler类中,实现多类共享,但MainPage中的订阅始终无法接收OnNext事件。若将Subject直接放在InfoStorageService类中则可正常工作,需要解决实例共享的问题。
代码示例
RxNetHandler类
public class RxNetHandler { public readonly ReplaySubject<List<InfoDto>> InfoSubject = new(1); }
InfoStorageService类
public class InfoStorageService { private readonly RxNetHandler _rxNetHandler = new(); private HttpClient _httpClient; private List<InfoDto> _infos = new(); public InfoStorageService() { InitHttps(); } public async Task GetInfosDetails() { var response = await _httpClient.GetAsync("https://jsonplaceholder.typicode.com/posts?userId=1"); var content = response.Content; if (response.IsSuccessStatusCode) { var jsonResponse = await content.ReadAsStringAsync(); _infos = JsonConvert.DeserializeObject<List<InfoDto>>(jsonResponse); } else { throw new Exception(((int)response.StatusCode).ToString() + " - " + response.ReasonPhrase); } _rxNetHandler.InfoSubject.OnNext(_infos); } }
MainPage类
public partial class MainPage : ContentPage { private readonly RxNetHandler _rxNetHandler = new(); private readonly InfoStorageService _infoStorage = new(); private List<InfoDto> _infos = new(); private IDisposable _disposed; public MainPage() { InitializeComponent(); InitData(); } protected override void OnAppearing() { _disposed = _rxNetHandler.InfoSubject.Subscribe( infos => { _infos = infos; }, () => { Console.WriteLine("[ completed ]"); } ); } private async void InitData() { await _infoStorage.GetInfosDetails(); InfoListView.ItemSelected += InfoListOnItemSelected; } }
问题原因
核心问题是RxNetHandler实例不共享:InfoStorageService和MainPage各自通过new()创建了独立的RxNetHandler对象,两者的InfoSubject是完全分离的实例。InfoStorageService调用OnNext时,是在自己的Subject上发送消息,而MainPage订阅的是另一个完全无关的Subject,因此无法接收到消息。
解决方案
方案1:单例模式确保实例唯一
修改RxNetHandler为单例,让所有类共享同一个实例:
public class RxNetHandler { private RxNetHandler() {} public static RxNetHandler Instance { get; } = new RxNetHandler(); public readonly ReplaySubject<List<InfoDto>> InfoSubject = new(1); }
修改InfoStorageService和MainPage的引用方式:
- InfoStorageService中:
private readonly RxNetHandler _rxNetHandler = RxNetHandler.Instance; - MainPage中:
private readonly RxNetHandler _rxNetHandler = RxNetHandler.Instance;
方案2:依赖注入传递实例
如果项目使用依赖注入(如.NET MAUI的内置DI),将RxNetHandler注册为单例:
在Program.cs中添加:
builder.Services.AddSingleton<RxNetHandler>();
修改类的构造函数实现注入:
// InfoStorageService构造函数 public InfoStorageService(RxNetHandler rxNetHandler) { _rxNetHandler = rxNetHandler; InitHttps(); } // MainPage构造函数 public MainPage(RxNetHandler rxNetHandler, InfoStorageService infoStorage) { _rxNetHandler = rxNetHandler; _infoStorage = infoStorage; InitializeComponent(); InitData(); }
方案3:手动传递同一实例
在MainPage中创建RxNetHandler实例,传递给InfoStorageService:
// MainPage构造函数 public MainPage() { _rxNetHandler = new RxNetHandler(); _infoStorage = new InfoStorageService(_rxNetHandler); InitializeComponent(); InitData(); } // InfoStorageService构造函数 public InfoStorageService(RxNetHandler rxNetHandler) { _rxNetHandler = rxNetHandler; InitHttps(); }
内容的提问来源于stack exchange,提问作者JBD
相关产品推荐
相关产品推荐

