WPF视图切换卡顿求助:API调用线程处理仍存延迟
问题根源分析
- 构造函数同步执行API调用:构造函数里直接调用了
RequestAllMarkets(id),该操作在UI线程同步执行网络请求,直接引发卡顿。 - 异步方法被阻塞调用:
Client.GetAsync(request).GetAwaiter().GetResult()会阻塞当前线程,即便在后台线程中,这种写法也会浪费线程资源,间接影响UI响应。 - 重复发起API请求:构造函数里既同步执行了一次
RequestAllMarkets(id),又启动了一个线程执行相同方法,重复请求额外增加了网络负载。 - 跨线程更新UI属性风险:
Asset和Markets的赋值操作在后台线程进行,跨线程更新UI绑定对象可能引发线程安全问题,加剧界面卡顿。
修复方案
核心优化点
- 用
async/await替代Thread和阻塞调用,高效处理异步网络请求 - 移除重复的API调用,确保每个请求仅执行一次
- 采用异步初始化模式,避免阻塞构造函数
- 借助
await自动回到UI上下文,安全更新绑定属性
修复后的代码
public class DetailsViewModel : ObservableObject { private ObservableCollection<Market> _markets; private Asset _asset; private readonly Uri _baseUri = new Uri("https://cryptingup.com/api/assets/"); public RestClient Client { get; set; } public ObservableCollection<Market> Markets { get => _markets; set { _markets = value; OnPropertyChanged(); } } public Asset Asset { get => _asset; set { _asset = value; OnPropertyChanged(); } } public DetailsViewModel(string id) { Client = new RestClient(); Markets = new ObservableCollection<Market>(); // 启动异步初始化任务,不阻塞构造函数 _ = InitializeDataAsync(id); } private async Task InitializeDataAsync(string id) { // 并行执行两个API请求,提升加载效率 var currencyTask = RequestCurrencyDetailsAsync(id); var marketsTask = RequestAllMarketsAsync(id); await Task.WhenAll(currencyTask, marketsTask); } private async Task RequestCurrencyDetailsAsync(string id) { Uri uri = new Uri(_baseUri, id); var request = new RestRequest(uri.ToString()); request.AddHeader("Accept", "application/json"); request.AddHeader("Content-Type", "application/json"); var response = await Client.GetAsync(request); var curemodel = JsonConvert.DeserializeObject<CurrencyModelCU>(response.Content); // await自动回到UI上下文,安全更新属性 Asset = curemodel.Asset; } private async Task RequestAllMarketsAsync(string id) { string marketPath = id + "/markets"; Uri uri = new Uri(_baseUri, marketPath); var request = new RestRequest(uri.ToString()); request.AddHeader("Accept", "application/json"); request.AddHeader("Content-Type", "application/json"); var response = await Client.GetAsync(request); var marmodel = JsonConvert.DeserializeObject<MarketsModel>(response.Content); ObservableCollection<Market> temp = new ObservableCollection<Market>(); for (int i = 0; i < 10; i++) { temp.Add(marmodel.Markets[i]); } Markets = temp; } }
额外优化建议
- 新增
IsLoading属性,初始化时设为true,所有请求完成后设为false,界面配合显示加载动画,提升用户体验。 - 在异步方法中添加
try/catch块,处理网络请求失败的情况,避免应用崩溃。 - 将
RestClient设计为单例或通过依赖注入复用,避免每次创建新实例,提升性能。
内容的提问来源于stack exchange,提问作者Palamar66
相关产品推荐
相关产品推荐

