Flutter多状态管理插件multi_state_bloc的使用

Flutter多状态管理插件multi_state_bloc的使用

multi_state_bloc 是一个简单易用的状态管理解决方案,允许您轻松管理子状态,而无需为每个状态创建单独的 bloc。它是一个扩展自 bloc 的抽象类。

为什么和如何使用?

每次发出状态时,视图都会收到通知,并且状态会存储在 bloc 中。您可以通过查看 bloc 的 state 属性轻松获取最后发出的状态。

随着应用程序的增长,状态类也会变得越来越复杂(构造函数、copyWith、props 等),您可以将状态类拆分为多个子状态类。但是 flutter_bloc 只能管理一个状态。

因此,如果发出了状态 A,然后是状态 B,那么 Bloc 的整体状态将是 B,并且除非重新实例化或保持在内存中,否则无法检索 A。

这就是 multi_state_bloc 的作用!它会在内存中保存对状态的引用,并允许您轻松检索这些状态。此外,一旦发出状态,它就会被拦截并自动更新。所以你不需要担心任何事情。

使用方法

继承 MultiStateBloc

首先,让您的 bloc 继承 MultiStateBloc。这是负责在内存中保存状态的类。

class Event {} 
class BaseState {}

class ConcreteStateA extends BaseState {}
class ConcreteStateB extends BaseState {}

class TestBloc extends MultiStateBloc<Event, BaseState> { 
    TestBloc(super.initialState);
}

注册事件和状态

接下来,注册 bloc 在其生命周期内需要使用的事件和状态。

class TestBloc extends MultiStateBloc<Event, BaseState> { 
    TestBloc(super.initialState) {
        on<Event>(handleTest);
        
        holdState(() => ConcreteStateA());
        holdState(() => ConcreteStateB());
    }
}

:::warning 注意 所有通过 holdState() 注册的状态都应该继承自同一个基类。 :::

在 bloc 内部检索状态

在 bloc 内部,您可以通过以下方式检索状态:

FutureOr<void> handleTest(event, emit) async {
    var stateA = states<ConcreteStateA>();
    
    emit(stateA.copyWith(...));
}

在视图内部检索状态

在视图内部,您可以通过以下方式检索状态:

BlocBuilder<TestBloc, BaseState>(
    builder: (context, state) {
        final bloc = context.read<TestBloc>();
        final stateA = bloc.states<ConcreteStateA>();
        
        // 处理 stateA
    }
)

过滤构建请求

如果您只想在特定状态下构建 UI,可以使用 buildWhen 来过滤构建请求:

BlocBuilder<TestBloc, BaseState>(
    buildWhen: (prev, next) => next is ConcreteStateA,
    builder: (context, state) {
        var stateA = state as ConcreteStateA;
        
        // 处理 stateA
    }
)

完整示例 Demo

以下是一个完整的示例 demo,展示了如何使用 multi_state_bloc 插件来管理多个状态。

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'test_bloc.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocProvider(
        create: (_) => TestBloc(BaseState())..add(Event()),
        child: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('multi_state_bloc Example')),
      body: Center(
        child: BlocBuilder<TestBloc, BaseState>(
          builder: (context, state) {
            final bloc = context.read<TestBloc>();
            final stateA = bloc.states<ConcreteStateA>();

            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('Current State: ${state.runtimeType}'),
                if (stateA != null) Text('ConcreteStateA Value: ${stateA.value}'),
              ],
            );
          },
        ),
      ),
    );
  }
}

test_bloc.dart

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:multi_state_bloc/multi_state_bloc.dart';

class Event {}

class BaseState {}

class ConcreteStateA extends BaseState {
  final String value;

  ConcreteStateA({this.value = 'Initial Value'});

  ConcreteStateA copyWith({String? value}) {
    return ConcreteStateA(value: value ?? this.value);
  }

  [@override](/user/override)
  List<Object?> get props => [value];
}

class ConcreteStateB extends BaseState {}

class TestBloc extends MultiStateBloc<Event, BaseState> {
  TestBloc(super.initialState) {
    on<Event>((event, emit) {
      var stateA = states<ConcreteStateA>();
      emit(stateA.copyWith(value: 'Updated Value'));
    });

    holdState(() => ConcreteStateA());
    holdState(() => ConcreteStateB());
  }
}

更多关于Flutter多状态管理插件multi_state_bloc的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter多状态管理插件multi_state_bloc的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用multi_state_bloc插件进行多状态管理的示例代码。multi_state_bloc 是一个用于在Flutter应用中处理复杂状态管理的库,它允许你使用BLoC(Business Logic Component)模式来管理应用的状态。

首先,确保你已经在你的pubspec.yaml文件中添加了multi_state_bloc依赖:

dependencies:
  flutter:
    sdk: flutter
  multi_state_bloc: ^最新版本号  # 请替换为实际最新版本号

然后,运行flutter pub get来安装依赖。

1. 创建State和Event类

首先,定义你的状态和事件类。例如,我们有一个简单的登录场景:

// event.dart
import 'package:multi_state_bloc/multi_state_bloc.dart';

class LoginEvent extends BlocEvent {
  final String username;
  final String password;

  LoginEvent(this.username, this.password);
}

// state.dart
import 'package:multi_state_bloc/multi_state_bloc.dart';

class LoginState extends BlocState {
  final String? message;
  final bool isLoading;
  final bool isSuccess;

  LoginState({this.message, this.isLoading = false, this.isSuccess = false});

  factory LoginState.initial() => LoginState();

  factory LoginState.loading() => LoginState(isLoading: true);

  factory LoginState.success() => LoginState(isSuccess: true);

  factory LoginState.error(String message) => LoginState(message: message);
}

2. 创建BLoC类

接下来,创建一个BLoC类来处理事件并生成状态:

// login_bloc.dart
import 'dart:async';
import 'package:multi_state_bloc/multi_state_bloc.dart';
import 'event.dart';
import 'state.dart';

class LoginBloc extends Bloc<LoginEvent, LoginState> {
  LoginBloc() : super(LoginState.initial()) {
    on<LoginEvent>((event, emit) async {
      emit(LoginState.loading());
      // 模拟异步操作,例如API调用
      await Future.delayed(Duration(seconds: 2));

      if (event.username == 'admin' && event.password == 'password') {
        emit(LoginState.success());
      } else {
        emit(LoginState.error('Invalid username or password'));
      }
    });
  }
}

3. 在UI中使用BLoC

最后,在你的UI组件中使用BLoC来显示不同的状态:

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'login_bloc.dart';
import 'state.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Login Example')),
        body: BlocProvider(
          create: (context) => LoginBloc(),
          child: LoginScreen(),
        ),
      ),
    );
  }
}

class LoginScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocConsumer<LoginBloc, LoginState>(
      listener: (context, state) {},
      buildWhen: (previous, current) => previous.isLoading != current.isLoading ||
          previous.isSuccess != current.isSuccess ||
          previous.message != current.message,
      builder: (context, state) {
        if (state.isLoading) {
          return Center(child: CircularProgressIndicator());
        } else if (state.isSuccess) {
          return Center(child: Text('Login Successful'));
        } else {
          return Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              TextField(
                decoration: InputDecoration(labelText: 'Username'),
                onChanged: (value) {
                  context.read<LoginBloc>().add(LoginEvent(value, state.message ?? ''));
                },
              ),
              SizedBox(height: 10),
              TextField(
                decoration: InputDecoration(labelText: 'Password'),
                obscureText: true,
                onChanged: (value) {
                  context.read<LoginBloc>().add(LoginEvent(state.message ?? '', value));
                },
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  context.read<LoginBloc>().add(LoginEvent(
                    (context.findAncestorStateOfType<TextField>()?.controller?.text ?? ''),
                    (context.findAncestorStateOfType<TextField>().last?.controller?.text ?? ''),
                  ));
                },
                child: Text('Login'),
              ),
              SizedBox(height: 10),
              Text(state.message ?? '')
            ],
          );
        }
      },
    );
  }
}

在这个示例中,我们创建了一个简单的登录BLoC,它可以处理登录事件并生成相应的状态。UI组件LoginScreen使用BlocProvider提供BLoC实例,并使用BlocConsumer来监听状态变化并相应地更新UI。

请根据你的实际需求调整代码。希望这个示例对你有帮助!

回到顶部