You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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)

这是轻量化的全局服务共享方案,适合单一实例的场景。

步骤:

  1. 添加get_it依赖到pubspec.yaml
  2. 初始化服务定位器并注册Api单例:
import 'package:get_it/get_it.dart';

final getIt = GetIt.instance;

void setupServiceLocator() {
  getIt.registerSingleton<Api>(Api());
}
  1. 在App启动时初始化:
void main() {
  setupServiceLocator();
  runApp(const MyApp());
}
  1. 在任意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刷新。

步骤:

  1. 添加provider依赖到pubspec.yaml
  2. 在App根节点注入Api实例:
void main() {
  runApp(
    Provider<Api>(
      create: (_) => Api(),
      child: const MyApp(),
    ),
  );
}
  1. 在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原生的状态共享方案,适合简单场景,不需要引入额外依赖。

步骤:

  1. 自定义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;
}
  1. 在App根节点包裹:
void main() {
  runApp(
    ApiProvider(
      api: Api(),
      child: const MyApp(),
    ),
  );
}
  1. 在Widget中获取实例:
// 在LoginPage或ConsumeApi中
final Api api = ApiProvider.of(context).api;

内容的提问来源于stack exchange,提问作者Dimitrios Desyllas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 06:15:14