Flutter使用Provider跳转至其他页面时实例数据丢失如何解决?
问题原因
- 实例不统一:你在
initState中调用ListingProvider().getListing()时创建了一个全新的ListingProvider临时实例,和build方法中通过Provider.of(context)获取的、全局注册的共享实例完全独立。你拉取到的4条数据只存在于这个临时实例中,共享实例的onDisplayListing自然为空。 - 异步时序问题:即便实例统一,
getListing是异步网络请求,首次执行build方法时请求还未完成,第一次打印也会返回空列表,只有等到请求完成触发notifyListeners()后,页面重绘时才能拿到数据。
解决方案
1. 修正Provider实例调用方式
不要在initState中新建实例,需要获取全局注册的共享实例来调用拉取方法,注意要加listen: false参数才能在生命周期方法中访问Provider:
@override initState() { super.initState(); final listingProvider = Provider.of<ListingProvider>(context, listen: false); listingProvider.getListing(widget.token); }
2. 确认顶层已正确注册Provider
请检查你的应用入口代码,确保已经在MaterialApp上层完成了ListingProvider的全局注册:
void main() { runApp( ChangeNotifierProvider( create: (context) => ListingProvider(), child: const MyApp(), ), ); }
3. 适配异步加载逻辑
由于网络请求是异步的,建议增加加载状态和空状态适配,避免首次加载空白:
首先在ListingProvider中新增加载状态
class ListingProvider extends ChangeNotifier { var url = Uri.parse('${Constants.apiUrl}listings/'); bool isLoading = false; List<Listing> onDisplayListing = []; ListingProvider() { print("Listing Provider inicializado"); } getListing(Token token) async { isLoading = true; notifyListeners(); try { var response = await http.get( url, headers: { 'content-type': 'application/json', 'accept': 'application/json', 'authorization': "Bearer ${token.token}" }, ); final nowListingResponse = ListingResponse.fromJson(response.body); onDisplayListing = nowListingResponse.results; } finally { isLoading = false; notifyListeners(); } } }
然后在页面中根据状态渲染不同内容
@override Widget build(BuildContext context) { final listingProvider = Provider.of<ListingProvider>(context); print(listingProvider.onDisplayListing); return Scaffold( appBar: AppBar( title: const Text("Find Shipments"), ), body: Center( child: listingProvider.isLoading ? const CircularProgressIndicator() : listingProvider.onDisplayListing.isEmpty ? const Text("暂无可用房源数据") : ListView.builder( itemCount: listingProvider.onDisplayListing.length, itemBuilder: (context, index) { final item = listingProvider.onDisplayListing[index]; // 替换为你自定义的Listing项组件 return ListTile(title: Text(item.name)); }, ), ), drawer: Drawer( child: ListView( padding: EdgeInsets.zero, children: [ MyHeaderDrawer( token: widget.token, ), myDrawerListOption(), ], ), ), ); }
内容的提问来源于stack exchange,提问作者Oliver Mendez
相关产品推荐
相关产品推荐

