Flutter应用:预加载存于Google Sheets的低频次更新主数据的最佳位置?
Flutter 预加载低变更主数据的优化方案
你的当前方案直接在main中调用异步preLoadData,会导致runApp立即执行,UI启动时数据大概率还未加载完成,容易出现空数据、页面异常等问题。针对URL列表这类每日仅需加载一次的低变更数据,推荐以下几个更优方案:
1. 闪屏页+FutureBuilder 等待加载完成
通过闪屏页过渡,直到数据加载完成再进入主页面,给用户明确的加载反馈:
void main() async { WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: FutureBuilder( future: preLoadData(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { // 自定义闪屏页,可添加加载动画 return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } else if (snapshot.hasError) { // 加载失败时显示重试页面 return Scaffold( body: Center( child: ElevatedButton( onPressed: () => preLoadData(), child: const Text("重试加载"), ), ), ); } else { // 数据就绪,进入主页面 return const HomePage(); } }, ), ); } }
2. 本地缓存+时间校验 实现每日加载
结合SharedPreferences或其他本地存储工具,记录最后加载时间,仅当超过24小时才请求Google Sheets,避免重复网络请求:
Future<void> preLoadData() async { final prefs = await SharedPreferences.getInstance(); final lastLoadTimestamp = prefs.getInt('last_load_time'); final now = DateTime.now().millisecondsSinceEpoch; const oneDayInMs = 86400000; // 24小时的毫秒数 List<String> urlList; if (lastLoadTimestamp == null || now - lastLoadTimestamp > oneDayInMs) { // 从Google Sheets拉取最新数据 urlList = await _fetchFromGoogleSheets(); // 保存到本地缓存 await prefs.setStringList('cached_urls', urlList); // 更新最后加载时间 await prefs.setInt('last_load_time', now); } else { // 直接读取本地缓存数据 urlList = prefs.getStringList('cached_urls') ?? []; } // 将数据存入全局可访问的位置(比如全局变量、状态管理工具) AppGlobals.urlList = urlList; } // 模拟Google Sheets数据请求 Future<List<String>> _fetchFromGoogleSheets() async { // 这里替换为实际的Google Sheets API请求逻辑 await Future.delayed(const Duration(seconds: 2)); return ["https://example1.com", "https://example2.com"]; } // 全局变量示例 class AppGlobals { static List<String> urlList = []; }
3. 状态管理工具的异步初始化
用Riverpod、Provider等状态管理工具封装数据加载逻辑,让页面自动监听数据状态变化,无需手动处理异步流程:
以Riverpod为例:
// 定义数据提供者 final urlListProvider = FutureProvider<List<String>>((ref) async { final prefs = await SharedPreferences.getInstance(); final lastLoadTimestamp = prefs.getInt('last_load_time'); final now = DateTime.now().millisecondsSinceEpoch; const oneDayInMs = 86400000; if (lastLoadTimestamp == null || now - lastLoadTimestamp > oneDayInMs) { final urlList = await _fetchFromGoogleSheets(); await prefs.setStringList('cached_urls', urlList); await prefs.setInt('last_load_time', now); return urlList; } else { return prefs.getStringList('cached_urls') ?? []; } }); // 主页面使用数据 class HomePage extends ConsumerWidget { const HomePage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final urlListAsync = ref.watch(urlListProvider); return urlListAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (err, stack) => Center( child: ElevatedButton( onPressed: () => ref.invalidate(urlListProvider), child: const Text("重试加载"), ), ), data: (urlList) { return ListView.builder( itemCount: urlList.length, itemBuilder: (ctx, index) => ListTile(title: Text(urlList[index])), ); }, ); } }
方案对比
- 闪屏页方案:适合需要确保数据完全加载后再进入主流程的场景,用户体验流畅
- 缓存+时间校验:核心是减少不必要的网络请求,降低服务器压力,同时保证数据每日更新
- 状态管理方案:代码解耦性更强,适合复杂应用,页面可自动响应数据变化
内容的提问来源于stack exchange,提问作者jigar1859
相关产品推荐
相关产品推荐

