MST

星途 面试题库

面试题:Flutter 网络请求并发时的 UI 更新策略

假设在一个Flutter应用中有多个网络请求需并发执行(例如同时获取用户信息、用户订单列表和用户收藏列表),在请求过程中,要实时展示每个请求的加载状态(如“正在获取用户信息...”等),全部请求完成后,根据请求结果更新相应的UI。请描述整体实现方案,并指出可能遇到的难点及如何解决。
31.7万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试

整体实现方案

  1. 状态管理
    • 使用ValueNotifierProvider等状态管理方案。以ValueNotifier为例,创建不同的ValueNotifier<bool>分别表示每个网络请求的加载状态,如ValueNotifier<bool> userInfoLoading = ValueNotifier<bool>(false);ValueNotifier<bool> orderListLoading = ValueNotifier<bool>(false);ValueNotifier<bool> favoriteListLoading = ValueNotifier<bool>(false);
    • 同时创建用于存储请求结果的变量,如UserInfo? userInfo;List<Order>? orderList;List<Favorite>? favoriteList;
  2. 网络请求
    • 使用httpdio库进行网络请求。以dio为例,定义获取用户信息、订单列表和收藏列表的方法,例如:
Future<UserInfo> fetchUserInfo() async {
  final response = await Dio().get('/user/info');
  return UserInfo.fromJson(response.data);
}

Future<List<Order>> fetchOrderList() async {
  final response = await Dio().get('/user/orders');
  return (response.data as List).map((e) => Order.fromJson(e)).toList();
}

Future<List<Favorite>> fetchFavoriteList() async {
  final response = await Dio().get('/user/favorites');
  return (response.data as List).map((e) => Favorite.fromJson(e)).toList();
}
  1. 并发执行
    • 使用Future.wait方法并发执行多个网络请求,例如:
try {
  userInfoLoading.value = true;
  orderListLoading.value = true;
  favoriteListLoading.value = true;
  final results = await Future.wait([
    fetchUserInfo(),
    fetchOrderList(),
    fetchFavoriteList()
  ]);
  userInfo = results[0];
  orderList = results[1];
  favoriteList = results[2];
} catch (e) {
  // 处理错误
} finally {
  userInfoLoading.value = false;
  orderListLoading.value = false;
  favoriteListLoading.value = false;
  // 更新UI
  setState(() {});
}
  1. UI展示
    • build方法中,根据ValueNotifier的状态显示加载信息,如:
ValueListenableBuilder<bool>(
  valueListenable: userInfoLoading,
  builder: (context, value, child) {
    if (value) {
      return Text('正在获取用户信息...');
    } else {
      return userInfo!= null? Text('用户信息:${userInfo!.name}') : Container();
    }
  },
),

类似地处理订单列表和收藏列表的加载状态及结果展示。

可能遇到的难点及解决方法

  1. 错误处理
    • 难点:在并发请求中,某个请求失败可能需要适当处理,并且不影响其他请求的继续执行和最终结果处理。
    • 解决方法:在Future.waitcatch块中,对不同请求的错误进行分类处理。可以自定义异常类型,在每个请求方法中抛出特定异常,例如:
Future<UserInfo> fetchUserInfo() async {
  try {
    final response = await Dio().get('/user/info');
    return UserInfo.fromJson(response.data);
  } catch (e) {
    throw UserInfoFetchException();
  }
}

Future.waitcatch块中:

try {
  //...
} catch (e) {
  if (e is UserInfoFetchException) {
    // 处理用户信息获取错误
  } else if (e is OrderListFetchException) {
    // 处理订单列表获取错误
  } else if (e is FavoriteListFetchException) {
    // 处理收藏列表获取错误
  }
}
  1. 内存管理
    • 难点:如果在请求过程中频繁更新状态,可能导致内存消耗增加和性能问题。
    • 解决方法:合理使用状态管理方案,避免不必要的状态更新。例如使用ValueNotifier时,确保只有在真正需要更新UI时才触发value的改变。同时,可以在页面销毁时及时释放相关资源,如取消未完成的网络请求(dio可以使用CancelToken来取消请求)。
  2. 网络延迟和超时
    • 难点:网络请求可能由于网络延迟或超时导致长时间等待,影响用户体验。
    • 解决方法:在网络请求库中设置合理的超时时间,如dio可以通过options设置超时:
Future<UserInfo> fetchUserInfo() async {
  final response = await Dio().get('/user/info', options: Options(timeout: Duration(seconds: 5)));
  return UserInfo.fromJson(response.data);
}

并且在界面上可以提供一个加载超时的提示,告知用户请求超时,让用户可以选择重试。