如何为Flutter所有Widget实现Api服务的全局共享?
问题描述
我创建了一个Api类:
class Api { // Token for authentication String bearerToken; // Generate a bearer token void login(String username,String password){ // Some Implementation hidden for simplicity } void refreshToken(){ // Some Implementation hidden for simplicity } void consumeAnEndpointUsingBearerToken(){ // Some Implementation hidden for simplicity } }
我还创建了一个登录Widget:
class LoginPage extends StatefulWidget { final String title; final Api api; const LoginPage({Key? key, required this.title, required this.api}) : super(key: key); @override State<LoginPage> createState() => _LoginPageState(api); } class _LoginPageState extends State<LoginPage> { String username = ''; String password = ''; final Api api; _LoginPageState(this.api); void __setUsername(username) { this.username = username; } void __setPassword(password) { this.password = password; } void _login() { setState(() { api.login(username,password); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ AppTextInput( hintText: 'Username', onChanged: __setUsername, ), AppTextInput( obscureText: true, hintText: 'Password', onChanged: __setPassword, ), AppButton( onPressed: _login, text: 'Login', ) ], ), ), ); } }
还有一个调用Api的页面:
class ConsumeApi extends StatelessWidget { const ConsumeApi({Key? key, required this.title, required this.api}) : super(key: key); // Render another Page }
目前我每次需要登录或调用Api时,都必须手动传递同一个Api实例至各个Widget。请问是否存在更优方案,可通过某种服务提供者实现Api服务的全局共享?
解决方案
1. 服务定位器(GetIt)
这是轻量化的全局服务共享方案,适合单一实例的场景。
步骤:
- 添加
get_it依赖到pubspec.yaml - 初始化服务定位器并注册Api单例:
import 'package:get_it/get_it.dart'; final getIt = GetIt.instance; void setupServiceLocator() { getIt.registerSingleton<Api>(Api()); }
- 在App启动时初始化:
void main() { setupServiceLocator(); runApp(const MyApp()); }
- 在任意Widget中直接获取实例:
// 修改LoginPage,无需传递api参数 class LoginPage extends StatefulWidget { final String title; const LoginPage({Key? key, required this.title}) : super(key: key); @override State<LoginPage> createState() => _LoginPageState(); } class _LoginPageState extends State<LoginPage> { String username = ''; String password = ''; final Api api = getIt<Api>(); // 直接获取实例 // 其余代码保持不变 } // 修改ConsumeApi class ConsumeApi extends StatelessWidget { const ConsumeApi({Key? key, required this.title}) : super(key: key); final Api api = getIt<Api>(); // 直接获取实例 // 页面逻辑代码 }
2. Provider状态管理库
适合需要监听Api状态变化(比如Token更新)的场景,能自动触发UI刷新。
步骤:
- 添加
provider依赖到pubspec.yaml - 在App根节点注入Api实例:
void main() { runApp( Provider<Api>( create: (_) => Api(), child: const MyApp(), ), ); }
- 在Widget中获取实例:
// 修改LoginPage class LoginPage extends StatefulWidget { final String title; const LoginPage({Key? key, required this.title}) : super(key: key); @override State<LoginPage> createState() => _LoginPageState(); } class _LoginPageState extends State<LoginPage> { String username = ''; String password = ''; late Api api; @override void didChangeDependencies() { super.didChangeDependencies(); // 无需监听状态变化时,listen设为false api = Provider.of<Api>(context, listen: false); } // 其余代码保持不变 } // 或者用Consumer简化监听逻辑 @override Widget build(BuildContext context) { return Consumer<Api>( builder: (context, api, child) { return Scaffold( // 直接使用api实例,状态变化时自动重建 ); }, ); }
3. 原生InheritedWidget(无需第三方库)
Flutter原生的状态共享方案,适合简单场景,不需要引入额外依赖。
步骤:
- 自定义InheritedWidget:
class ApiProvider extends InheritedWidget { final Api api; const ApiProvider({Key? key, required this.api, required Widget child}) : super(key: key, child: child); static ApiProvider of(BuildContext context) { final ApiProvider? result = context.dependOnInheritedWidgetOfExactType<ApiProvider>(); assert(result != null, 'No ApiProvider found in context'); return result!; } @override bool updateShouldNotify(ApiProvider oldWidget) => api != oldWidget.api; }
- 在App根节点包裹:
void main() { runApp( ApiProvider( api: Api(), child: const MyApp(), ), ); }
- 在Widget中获取实例:
// 在LoginPage或ConsumeApi中 final Api api = ApiProvider.of(context).api;
内容的提问来源于stack exchange,提问作者Dimitrios Desyllas
相关产品推荐
相关产品推荐

