Flutter中的狀態(tài)管理

1. 狀態(tài)管理基礎

1.1 什么是狀態(tài)

在Flutter中,狀態(tài)(State)指的是應用在特定時間點的數(shù)據(jù)快照。這些數(shù)據(jù)可能包括:

  • 用戶數(shù)據(jù)(如個人資料、設置偏好)
  • 應用數(shù)據(jù)(如產(chǎn)品列表、購物車內(nèi)容)
  • UI狀態(tài)(如加載狀態(tài)、表單驗證、按鈕啟用/禁用)
  • 導航狀態(tài)(如當前頁面、導航歷史)

狀態(tài)可以分為兩種主要類型:

  1. 短暫狀態(tài)(Ephemeral State):也稱為UI狀態(tài)或局部狀態(tài),僅影響單個widget
  2. 應用狀態(tài)(App State):跨多個widget共享的狀態(tài),影響應用的多個部分

1.2 為什么需要狀態(tài)管理

隨著應用復雜性增加,出現(xiàn)了以下挑戰(zhàn):

  • 狀態(tài)分散在應用的不同部分
  • 組件間需要共享狀態(tài)
  • 需要在組件樹不同層級訪問狀態(tài)
  • 狀態(tài)變化需要反映到UI上
  • 確保狀態(tài)一致性和可預測性

良好的狀態(tài)管理解決方案應該:

  • 使狀態(tài)變化可預測
  • 減少組件之間的耦合
  • 提高代碼可測試性
  • 使應用更易于維護和擴展

2. Flutter中的狀態(tài)管理方案

2.1 setState (基礎方案)

最簡單的狀態(tài)管理方式,適用于管理局部UI狀態(tài)。

基本用法

class CounterWidget extends StatefulWidget {
  @override
  _CounterWidgetState createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('計數(shù): $_counter'),
        ElevatedButton(
          onPressed: _incrementCounter,
          child: Text('增加'),
        )
      ],
    );
  }
}

優(yōu)缺點

優(yōu)點

  • 簡單直觀,是Flutter內(nèi)置的解決方案
  • 不需要額外的包依賴
  • 適合簡單的UI狀態(tài)管理

缺點

  • 不適合跨widget共享狀態(tài)
  • 可能導致widget重建過多(性能問題)
  • 在復雜應用中會導致代碼難以維護

2.2 InheritedWidget

Flutter提供的用于向下傳遞數(shù)據(jù)的內(nèi)置機制,是許多高級狀態(tài)管理方案的基礎。

基本用法

class CounterModel extends InheritedWidget {
  final int counter;
  final Function incrementCounter;

  CounterModel({
    required this.counter,
    required this.incrementCounter,
    required Widget child,
  }) : super(child: child);

  static CounterModel of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<CounterModel>()!;
  }

  @override
  bool updateShouldNotify(CounterModel oldWidget) {
    return counter != oldWidget.counter;
  }
}

class CounterProvider extends StatefulWidget {
  final Widget child;
  
  CounterProvider({required this.child});
  
  @override
  _CounterProviderState createState() => _CounterProviderState();
}

class _CounterProviderState extends State<CounterProvider> {
  int _counter = 0;
  
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return CounterModel(
      counter: _counter,
      incrementCounter: _incrementCounter,
      child: widget.child,
    );
  }
}

// 使用
class CounterScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counterModel = CounterModel.of(context);
    return Column(
      children: [
        Text('計數(shù): ${counterModel.counter}'),
        ElevatedButton(
          onPressed: () => counterModel.incrementCounter(),
          child: Text('增加'),
        ),
      ],
    );
  }
}

優(yōu)缺點

優(yōu)點

  • Flutter核心機制,無需額外依賴
  • 提供從上到下的數(shù)據(jù)流
  • 當數(shù)據(jù)變化時自動重建依賴的widgets

缺點

  • 需要大量樣板代碼
  • 組合多個InheritedWidget比較困難
  • 不提供狀態(tài)管理,只提供數(shù)據(jù)傳遞

2.3 Provider

在InheritedWidget基礎上構建的狀態(tài)管理庫,是Flutter團隊推薦的方案之一。

基本用法

// 1. 定義數(shù)據(jù)模型
class CounterModel extends ChangeNotifier {
  int _count = 0;
  
  int get count => _count;
  
  void increment() {
    _count++;
    notifyListeners();
  }
}

// 2. 提供狀態(tài)
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => CounterModel(),
      child: MyApp(),
    ),
  );
}

// 3. 消費狀態(tài)
class CounterDisplay extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 方式1:使用Consumer
    return Consumer<CounterModel>(
      builder: (context, counter, child) {
        return Text('計數(shù): ${counter.count}');
      },
    );
  }
}

class CounterIncrement extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 方式2:使用Provider.of
    return ElevatedButton(
      onPressed: () {
        Provider.of<CounterModel>(context, listen: false).increment();
      },
      child: Text('增加'),
    );
  }
}

// 多個Provider嵌套
void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => CounterModel()),
        ChangeNotifierProvider(create: (context) => UserModel()),
        Provider(create: (context) => SomeService()),
      ],
      child: MyApp(),
    ),
  );
}

Provider的變體

  • Provider: 基本的Provider,不會在值變化時重建widget
  • ChangeNotifierProvider: 監(jiān)聽ChangeNotifier,當notifyListeners()被調(diào)用時重建widget
  • FutureProvider: 提供Future的結果
  • StreamProvider: 提供Stream的最新值
  • ListenableProvider: 監(jiān)聽Listenable對象,適用于不是ChangeNotifier的情況
  • ValueListenableProvider: 專門用于ValueListenable

優(yōu)缺點

優(yōu)點

  • 易于學習和使用
  • 良好的性能(精確控制重建)
  • 與Flutter很好地集成
  • 支持依賴注入
  • 豐富的文檔和社區(qū)支持
  • 由Flutter團隊推薦

缺點

  • 復雜應用中可能需要創(chuàng)建大量模型類
  • 處理深層次嵌套狀態(tài)需要精心設計
  • 狀態(tài)模型之間的依賴需要手動管理

2.4 Riverpod

Provider的進化版,解決了Provider的一些限制。

基本用法

// 1. 定義Provider
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
  return CounterNotifier();
});

class CounterNotifier extends StateNotifier<int> {
  CounterNotifier() : super(0);
  
  void increment() => state = state + 1;
}

// 2. 在應用頂層使用ProviderScope
void main() {
  runApp(
    ProviderScope(
      child: MyApp(),
    ),
  );
}

// 3. 使用狀態(tài)
class CounterDisplay extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Text('計數(shù): $count');
  }
}

class CounterIncrement extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ElevatedButton(
      onPressed: () {
        ref.read(counterProvider.notifier).increment();
      },
      child: Text('增加'),
    );
  }
}

Riverpod的特點

  • 完全類型安全,沒有運行時錯誤
  • 不需要上下文(context)來訪問providers
  • 可以在任何地方(甚至在initState外部)訪問providers
  • 支持自動釋放未使用的狀態(tài)
  • 輕松處理異步狀態(tài)
  • 簡化測試

優(yōu)缺點

優(yōu)點

  • 解決了Provider的上下文依賴問題
  • 提供真正的類型安全
  • 更好的異步狀態(tài)處理
  • 簡化代碼復用

缺點

  • 學習曲線稍陡
  • 與Flutter不同的語法(ref vs context)
  • 需要特殊widget(ConsumerWidget等)

2.5 BLoC/Cubit

基于流(Stream)的狀態(tài)管理方案,將業(yè)務邏輯與UI分離。

Cubit (簡化的BLoC)

// 1. 定義狀態(tài)
class CounterState {
  final int count;
  
  CounterState(this.count);
}

// 2. 創(chuàng)建Cubit
class CounterCubit extends Cubit<CounterState> {
  CounterCubit() : super(CounterState(0));
  
  void increment() {
    emit(CounterState(state.count + 1));
  }
}

// 3. 提供Cubit
void main() {
  runApp(
    BlocProvider(
      create: (context) => CounterCubit(),
      child: MyApp(),
    ),
  );
}

// 4. 使用狀態(tài)
class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocBuilder<CounterCubit, CounterState>(
        builder: (context, state) {
          return Text('計數(shù): ${state.count}');
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.read<CounterCubit>().increment(),
        child: Icon(Icons.add),
      ),
    );
  }
}

BLoC (完整版)

// 1. 定義事件
abstract class CounterEvent {}
class IncrementEvent extends CounterEvent {}

// 2. 創(chuàng)建BLoC
class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterState(0)) {
    on<IncrementEvent>((event, emit) {
      emit(CounterState(state.count + 1));
    });
  }
}

// 3. 提供BLoC
void main() {
  runApp(
    BlocProvider(
      create: (context) => CounterBloc(),
      child: MyApp(),
    ),
  );
}

// 4. 使用狀態(tài)
class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocBuilder<CounterBloc, CounterState>(
        builder: (context, state) {
          return Text('計數(shù): ${state.count}');
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.read<CounterBloc>().add(IncrementEvent()),
        child: Icon(Icons.add),
      ),
    );
  }
}

優(yōu)缺點

優(yōu)點

  • 狀態(tài)、事件和業(yè)務邏輯的強分離
  • 高度可測試性
  • 反應式編程方式
  • 復雜狀態(tài)轉(zhuǎn)換的良好處理

缺點

  • 較陡峭的學習曲線
  • 增加了大量樣板代碼
  • 小型應用中可能過于復雜

2.6 Redux

基于單向數(shù)據(jù)流的狀態(tài)管理方案,源自Web開發(fā)。

基本用法

// 1. 定義應用狀態(tài)
class AppState {
  final int counter;
  
  AppState({this.counter = 0});
  
  AppState copyWith({int? counter}) {
    return AppState(
      counter: counter ?? this.counter,
    );
  }
}

// 2. 定義Action
class IncrementAction {}

// 3. 創(chuàng)建Reducer
AppState reducer(AppState state, dynamic action) {
  if (action is IncrementAction) {
    return state.copyWith(counter: state.counter + 1);
  }
  return state;
}

// 4. 創(chuàng)建Store
final store = Store<AppState>(
  reducer,
  initialState: AppState(),
);

// 5. 提供Store
void main() {
  runApp(
    StoreProvider<AppState>(
      store: store,
      child: MyApp(),
    ),
  );
}

// 6. 使用狀態(tài)
class CounterDisplay extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StoreConnector<AppState, int>(
      converter: (store) => store.state.counter,
      builder: (context, counter) {
        return Text('計數(shù): $counter');
      },
    );
  }
}

class CounterIncrement extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StoreConnector<AppState, VoidCallback>(
      converter: (store) {
        return () => store.dispatch(IncrementAction());
      },
      builder: (context, callback) {
        return ElevatedButton(
          onPressed: callback,
          child: Text('增加'),
        );
      },
    );
  }
}

優(yōu)缺點

優(yōu)點

  • 可預測的單向數(shù)據(jù)流
  • 集中式狀態(tài)管理
  • 良好的調(diào)試能力(時間旅行調(diào)試)
  • 中間件支持(處理副作用)

缺點

  • 大量樣板代碼
  • 較陡峭的學習曲線
  • 簡單操作需要多處修改

2.7 GetX

輕量級且功能強大的狀態(tài)管理、路由管理和依賴注入解決方案。

基本用法

// 1. 定義控制器
class CounterController extends GetxController {
  var count = 0.obs;  // 使用.obs創(chuàng)建可觀察變量
  
  void increment() {
    count++;  // 自動更新UI
  }
}

// 2. 初始化
void main() {
  runApp(
    GetMaterialApp(  // 替換MaterialApp
      home: Home(),
    ),
  );
}

// 3. 使用狀態(tài) - 方式1:GetX
class CounterDisplay1 extends StatelessWidget {
  final controller = Get.put(CounterController());  // 注入控制器
  
  @override
  Widget build(BuildContext context) {
    return GetX<CounterController>(
      builder: (controller) {
        return Text('計數(shù): ${controller.count.value}');
      },
    );
  }
}

// 3. 使用狀態(tài) - 方式2:Obx(更簡潔)
class CounterDisplay2 extends StatelessWidget {
  final controller = Get.find<CounterController>();  // 查找已注入的控制器
  
  @override
  Widget build(BuildContext context) {
    return Obx(() => Text('計數(shù): ${controller.count.value}'));
  }
}

// 4. 更新狀態(tài)
class CounterIncrement extends StatelessWidget {
  final controller = Get.find<CounterController>();
  
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: controller.increment,
      child: Text('增加'),
    );
  }
}

優(yōu)缺點

優(yōu)點

  • 簡單易用,API簡潔
  • 整合路由管理、依賴注入和狀態(tài)管理
  • 高性能(只重建需要的widgets)
  • 不需要上下文(context)
  • 低樣板代碼量

缺點

  • 非標準Flutter方法
  • 社區(qū)支持不如主流方案
  • 架構可能導致濫用全局狀態(tài)

2.8 MobX

基于可觀察對象的狀態(tài)管理庫,源自React生態(tài)系統(tǒng)。

基本用法

// 1. 定義Store
part 'counter_store.g.dart';  // 代碼生成部分

class CounterStore = _CounterStore with _$CounterStore;

abstract class _CounterStore with Store {
  @observable
  int count = 0;
  
  @computed
  bool get isEven => count % 2 == 0;
  
  @action
  void increment() {
    count++;
  }
}

// 2. 創(chuàng)建和提供Store
final counterStore = CounterStore();

// 3. 使用Store
class CounterDisplay extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Observer(
      builder: (_) => Column(
        children: [
          Text('計數(shù): ${counterStore.count}'),
          Text('是偶數(shù): ${counterStore.isEven ? "是" : "否"}'),
        ],
      ),
    );
  }
}

class CounterIncrement extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: counterStore.increment,
      child: Text('增加'),
    );
  }
}

優(yōu)缺點

優(yōu)點

  • 基于可觀察模式,精確更新
  • 計算屬性支持
  • 響應式編程體驗
  • 與React MobX相似(熟悉React的開發(fā)者易上手)

缺點

  • 需要代碼生成
  • 需要特殊裝飾器處理
  • 學習曲線中等

3. 狀態(tài)管理方案比較

3.1 功能比較

特性/方案 setState InheritedWidget Provider Riverpod BLoC Redux GetX MobX
復雜度 低-中
學習曲線 很淺 中等 中等 陡峭 陡峭 中等
樣板代碼 很少 很多 很少 中等
性能 中等 良好 良好 良好 良好 良好 良好 良好
可測試性 很高 很高
社區(qū)支持 很高 很高
適合項目規(guī)模 小型 小-中型 小-大型 小-大型 中-大型 中-大型 小-大型 小-大型
開發(fā)團隊 Flutter Flutter Flutter社區(qū) Flutter社區(qū) Flutter社區(qū) Flutter社區(qū) GetX團隊 Flutter社區(qū)

3.2 適用場景

  • setState: 簡單的組件內(nèi)狀態(tài)管理,原型開發(fā)
  • Provider: 中小型應用,需要共享狀態(tài)但不復雜
  • Riverpod: 需要更好類型安全和依賴管理的應用
  • BLoC/Cubit: 大型應用,有復雜業(yè)務邏輯,團隊協(xié)作
  • Redux: 需要嚴格狀態(tài)控制,喜歡函數(shù)式編程
  • GetX: 需要快速開發(fā),簡潔代碼,及路由管理
  • MobX: 喜歡響應式編程,熟悉MobX從React遷移

4. 狀態(tài)管理最佳實踐

4.1 通用原則

  1. 基于復雜度選擇工具

    • 簡單狀態(tài)使用簡單工具(setState)
    • 不要過早優(yōu)化或引入復雜框架
  2. 狀態(tài)分層

    • 區(qū)分UI狀態(tài)和業(yè)務狀態(tài)
    • 局部狀態(tài)使用局部解決方案
    • 全局狀態(tài)使用全局方案
  3. 單一數(shù)據(jù)源

    • 每個狀態(tài)應該有一個明確的來源
    • 避免狀態(tài)重復
  4. 不可變狀態(tài)

    • 不直接修改狀態(tài)
    • 創(chuàng)建新狀態(tài)來替換舊狀態(tài)
  5. 最小化重建

    • 只重建依賴變化狀態(tài)的UI部分
    • 將大型widget拆分為小部件

4.2 代碼組織

  1. 關注點分離

    • 將UI、業(yè)務邏輯和數(shù)據(jù)訪問分開
    • 使用分層架構(UI層、業(yè)務層、數(shù)據(jù)層)
  2. 模塊化

    • 按功能組織代碼,而不是按類型
    • 每個模塊包含其UI和狀態(tài)管理
  3. 依賴注入

    • 使用依賴注入降低組件耦合
    • 便于測試和替換實現(xiàn)

4.3 常見反模式

  1. 狀態(tài)過度集中

    • 將所有狀態(tài)放在一個巨大的類中
    • 導致不必要的重建和性能問題
  2. 狀態(tài)過度分散

    • 沒有合理組織相關狀態(tài)
    • 導致狀態(tài)管理混亂,難以維護
  3. 過早優(yōu)化

    • 在不需要復雜解決方案時使用它們
    • 增加不必要的學習和開發(fā)成本
  4. 濫用全局狀態(tài)

    • 將應該是局部的狀態(tài)放到全局
    • 導致組件緊密耦合

5. 實際案例

5.1 購物車應用(使用Provider)

// 定義產(chǎn)品模型
class Product {
  final int id;
  final String name;
  final double price;
  
  Product({required this.id, required this.name, required this.price});
}

// 購物車模型
class CartModel extends ChangeNotifier {
  final List<Product> _items = [];
  
  List<Product> get items => List.unmodifiable(_items);
  
  double get totalPrice => 
    _items.fold(0, (sum, product) => sum + product.price);
  
  void add(Product product) {
    _items.add(product);
    notifyListeners();
  }
  
  void removeAt(int index) {
    _items.removeAt(index);
    notifyListeners();
  }
  
  void clear() {
    _items.clear();
    notifyListeners();
  }
}

// 產(chǎn)品目錄模型
class CatalogModel extends ChangeNotifier {
  final List<Product> _products = [
    Product(id: 1, name: "商品1", price: 10.0),
    Product(id: 2, name: "商品2", price: 15.0),
    Product(id: 3, name: "商品3", price: 20.0),
  ];
  
  List<Product> get products => List.unmodifiable(_products);
}

// 應用入口
void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => CatalogModel()),
        ChangeNotifierProvider(create: (context) => CartModel()),
      ],
      child: MyApp(),
    ),
  );
}

// 產(chǎn)品列表頁面
class ProductListPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final catalog = Provider.of<CatalogModel>(context);
    final cart = Provider.of<CartModel>(context, listen: false);
    
    return Scaffold(
      appBar: AppBar(
        title: Text('產(chǎn)品列表'),
        actions: [
          IconButton(
            icon: Icon(Icons.shopping_cart),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => CartPage()),
              );
            },
          ),
        ],
      ),
      body: ListView.builder(
        itemCount: catalog.products.length,
        itemBuilder: (context, index) {
          final product = catalog.products[index];
          return ListTile(
            title: Text(product.name),
            subtitle: Text('¥${product.price}'),
            trailing: IconButton(
              icon: Icon(Icons.add_shopping_cart),
              onPressed: () {
                cart.add(product);
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text('${product.name} 已添加到購物車')),
                );
              },
            ),
          );
        },
      ),
    );
  }
}

// 購物車頁面
class CartPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('購物車')),
      body: Consumer<CartModel>(
        builder: (context, cart, child) {
          if (cart.items.isEmpty) {
            return Center(child: Text('購物車為空'));
          }
          
          return Column(
            children: [
              Expanded(
                child: ListView.builder(
                  itemCount: cart.items.length,
                  itemBuilder: (context, index) {
                    final product = cart.items[index];
                    return ListTile(
                      title: Text(product.name),
                      subtitle: Text('¥${product.price}'),
                      trailing: IconButton(
                        icon: Icon(Icons.remove_circle),
                        onPressed: () {
                          cart.removeAt(index);
                        },
                      ),
                    );
                  },
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text('總計: ¥${cart.totalPrice}', 
                      style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                    ),
                    ElevatedButton(
                      onPressed: () {
                        // 結賬邏輯
                        cart.clear();
                        Navigator.pop(context);
                        ScaffoldMessenger.of(context).showSnackBar(
                          SnackBar(content: Text('訂單已完成')),
                        );
                      },
                      child: Text('結賬'),
                    ),
                  ],
                ),
              ),
            ],
          );
        },
      ),
    );
  }
}

5.2 認證應用(使用BLoC)

// 認證狀態(tài)
abstract class AuthState {}
class AuthInitial extends AuthState {}
class AuthLoading extends AuthState {}
class AuthAuthenticated extends AuthState {
  final User user;
  AuthAuthenticated(this.user);
}
class AuthUnauthenticated extends AuthState {
  final String? message;
  AuthUnauthenticated([this.message]);
}

// 認證事件
abstract class AuthEvent {}
class LoginEvent extends AuthEvent {
  final String username;
  final String password;
  LoginEvent(this.username, this.password);
}
class LogoutEvent extends AuthEvent {}

// 用戶模型
class User {
  final String id;
  final String name;
  
  User({required this.id, required this.name});
}

// 認證服務
class AuthService {
  Future<User> login(String username, String password) async {
    // 模擬網(wǎng)絡請求
    await Future.delayed(Duration(seconds: 2));
    
    if (username == 'admin' && password == 'password') {
      return User(id: '1', name: 'Admin User');
    } else {
      throw Exception('用戶名或密碼錯誤');
    }
  }
  
  Future<void> logout() async {
    await Future.delayed(Duration(seconds: 1));
    // 清除令牌等
  }
}

// 認證BLoC
class AuthBloc extends Bloc<AuthEvent, AuthState> {
  final AuthService authService;
  
  AuthBloc(this.authService) : super(AuthInitial()) {
    on<LoginEvent>(_onLogin);
    on<LogoutEvent>(_onLogout);
  }
  
  Future<void> _onLogin(LoginEvent event, Emitter<AuthState> emit) async {
    emit(AuthLoading());
    
    try {
      final user = await authService.login(event.username, event.password);
      emit(AuthAuthenticated(user));
    } catch (e) {
      emit(AuthUnauthenticated(e.toString()));
    }
  }
  
  Future<void> _onLogout(LogoutEvent event, Emitter<AuthState> emit) async {
    emit(AuthLoading());
    
    try {
      await authService.logout();
      emit(AuthUnauthenticated());
    } catch (e) {
      emit(AuthUnauthenticated(e.toString()));
    }
  }
}

// 應用入口
void main() {
  runApp(
    BlocProvider(
      create: (context) => AuthBloc(AuthService()),
      child: MyApp(),
    ),
  );
}

// 主應用
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocBuilder<AuthBloc, AuthState>(
        builder: (context, state) {
          if (state is AuthAuthenticated) {
            return HomePage(user: state.user);
          }
          return LoginPage();
        },
      ),
    );
  }
}

// 登錄頁面
class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final _usernameController = TextEditingController();
  final _passwordController = TextEditingController();
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('登錄')),
      body: BlocConsumer<AuthBloc, AuthState>(
        listener: (context, state) {
          if (state is AuthUnauthenticated && state.message != null) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text(state.message!)),
            );
          }
        },
        builder: (context, state) {
          return Padding(
            padding: EdgeInsets.all(16.0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                TextField(
                  controller: _usernameController,
                  decoration: InputDecoration(labelText: '用戶名'),
                ),
                TextField(
                  controller: _passwordController,
                  decoration: InputDecoration(labelText: '密碼'),
                  obscureText: true,
                ),
                SizedBox(height: 20),
                if (state is AuthLoading)
                  CircularProgressIndicator()
                else
                  ElevatedButton(
                    onPressed: () {
                      context.read<AuthBloc>().add(
                        LoginEvent(
                          _usernameController.text,
                          _passwordController.text,
                        ),
                      );
                    },
                    child: Text('登錄'),
                  ),
              ],
            ),
          );
        },
      ),
    );
  }
}

// 主頁
class HomePage extends StatelessWidget {
  final User user;
  
  HomePage({required this.user});
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('主頁'),
        actions: [
          IconButton(
            icon: Icon(Icons.logout),
            onPressed: () {
              context.read<AuthBloc>().add(LogoutEvent());
            },
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('歡迎, ${user.name}!', style: TextStyle(fontSize: 24)),
            Text('ID: ${user.id}'),
          ],
        ),
      ),
    );
  }
}

6. 結論

Flutter中的狀態(tài)管理沒有一種通用的最佳解決方案,選擇取決于多種因素:

  • 項目規(guī)模和復雜度
  • 團隊經(jīng)驗和熟悉度
  • 性能需求
  • 開發(fā)速度需求
  • 代碼可維護性需求
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容