Flutter隔离区数据管理插件isolate_bloc的使用

发布于 1周前 作者 vueper 来自 Flutter

Flutter隔离区数据管理插件isolate_bloc的使用

概述

该插件的目标是简化在Flutter应用中使用BLoC(Business Logic Component)和Isolate的方式。与其它BLoC实现不同的是,这个包中的blocs运行在Isolate中,不会拖慢UI。

索引

  • 注意事项
  • Bloc和Cubit
  • 创建
    • IsolateCubit
    • IsolateBloc
  • 注册一个Bloc或Cubit
  • 在UI中使用Bloc或Cubit
  • 全部API
    • IsolateBlocWrapper
    • 初始化
    • 创建新的Bloc实例
    • 使用Bloc
    • Blocs观察者
    • 在另一个Bloc中使用Bloc
    • 使用平台通道
  • 示例
  • 文章
  • 帮助工具
  • 致谢

注意事项

建议先了解Isolates的优点和缺点。简而言之,Isolates共享内存,因此不可变对象在传输到另一个Isolate时不会被复制。虽然现在可以放心使用它们,但仍然存在一些限制和开销。

Bloc和Cubit

在Bloc中,事件按顺序处理。它接收一个事件并响应以mapEventToState中的状态流。直到流结束前,新事件的处理不会开始。 在Cubit中,事件在onEventReceived中异步接收,并通过emit函数返回状态。

创建

IsolateCubit
/// 计数器Cubit,使用`CountEvent`和`int`状态。
class CounterCubit extends IsolateCubit<CountEvent, int> {
  /// `CounterCubit`的初始状态为0。
  CounterCubit() : super(0);

  /// 当接收到`CountEvent`时,通过`state`访问当前状态
  /// 并通过`emit`发出新的状态。
  [@override](/user/override)
  void onEventReceived(CountEvent event) {
    emit(event == CountEvent.increment ? state + 1 : state - 1);
  }
}
IsolateBloc
class CounterBloc extends IsolateBloc<CountEvent, int> {
  /// `CounterBloc`的初始状态为0。
  CounterBloc() : super(0);

  /// 当接收到`CountEvent`时,通过`state`访问当前状态
  /// 并通过`yield`发出新的状态。
  Stream<int> mapEventToState(CountEvent event) async* {
    yield event == CountEvent.increment ? state + 1 : state - 1;
  }
}

注册一个Bloc或Cubit

为了能够创建Bloc,需要注册它。可以通过register函数完成。

void main() async {
  await initialize(isolatedFunc);
  ...
}

/// 全局函数用于注册blocs或cubits并在Isolate中调用
void isolatedFunc() {
  /// 注册一个bloc以便在主Isolate中创建
  register<CounterBloc, int>(create: () => CounterBloc());
}

如果不想创建所有注册的blocs的单个实例以获取其初始状态,可以在register函数中提供初始状态。

register<CounterBloc, int>(
  create: () => CounterBloc(), 
  initialState: 0,
)

在UI中使用Bloc或Cubit

YourWidget(
  /// 创建CounterBloc并将其向下传递到小部件树
  child: IsolateBlocProvider<CounterBloc, int>(
    child: CounterScreen(),
  ),
)
...
class CounterScreen extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter'),
      ),
      body: Center(
        /// 监听CounterBloc的状态
        child: IsolateBlocListener<CounterBloc, int>(
          listener: (context, state) => print("New bloc state: $state"),
          /// 根据CounterBloc的状态构建小部件
          child: IsolateBlocBuilder<CounterBloc, int>(
            builder: (context, state) {
              return Text('You tapped $state times');
            },
          ),
        ),
      ),
      floatingActionButton: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          FloatingActionButton(
            heroTag: 'Increment',
            /// 使用扩展方法获取bloc并添加新事件
            onPressed: () => context.isolateBloc<CounterBloc, int>().add(CountEvent.increment),
            child: Icon(Icons.add),
          ),
          SizedBox(height: 10),
          FloatingActionButton(
            heroTag: 'Decrement',
            /// 使用provider类获取bloc并添加新事件
            onPressed: () => IsolateBlocProvider.of<CounterBloc, int>(context).add(CountEvent.decrement),
            child: Icon(Icons.remove),
          ),
        ],
      ),
    );
  }
}

完整示例代码

以下是完整的示例代码,展示了如何使用isolate_bloc插件来实现一个简单的计数器应用:

import 'package:flutter/material.dart';
import 'package:isolate_bloc/isolate_bloc.dart';

Future<void> main(List<String> arguments) async {
  // 初始化Isolate和注册blocs
  await initialize(isolatedFunc);
  runApp(
    MaterialApp(
      home: IsolateBlocProvider<CounterCubit, int>(
        child: CounterScreen(),
      ),
    ),
  );
}

class CounterScreen extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Counter'),
      ),
      body: Center(
        child: IsolateBlocListener<CounterCubit, int>(
          listener: (context, state) => print('New bloc state: $state'),
          child: IsolateBlocBuilder<CounterCubit, int>(
            builder: (context, state) {
              return Text('You tapped $state times');
            },
          ),
        ),
      ),
      floatingActionButton: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          FloatingActionButton(
            heroTag: 'Increment',
            onPressed: () => context
                .isolateBloc<CounterCubit, int>()
                .add(CountEvent.increment),
            child: const Icon(Icons.add),
          ),
          const SizedBox(height: 10),
          FloatingActionButton(
            heroTag: 'Decrement',
            onPressed: () => context
                .isolateBloc<CounterCubit, int>()
                .add(CountEvent.decrement),
            child: const Icon(Icons.remove),
          ),
        ],
      ),
    );
  }
}

Future<void> isolatedFunc() async {
  // 设置Bloc观察者
  IsolateBloc.observer = SimpleBlocObserver();
  // 注册CounterCubit
  register<CounterCubit, int>(create: () => CounterCubit());
}

// 定义CounterCubit
class CounterCubit extends IsolateCubit<CountEvent, int> {
  CounterCubit() : super(0);

  [@override](/user/override)
  void onEventReceived(CountEvent event) {
    emit(event == CountEvent.increment ? state + 1 : state - 1);
  }
}

// 定义CountEvent枚举
enum CountEvent {
  increment,
  decrement,
}

// 定义SimpleBlocObserver用于观察Bloc的行为
class SimpleBlocObserver extends IsolateBlocObserver {
  [@override](/user/override)
  void onClose(IsolateBlocBase bloc) {
    print('New instance of ${bloc.runtimeType}');
    super.onClose(bloc);
  }

  [@override](/user/override)
  void onEvent(IsolateBlocBase bloc, Object? event) {
    print('New $event for $bloc');
    super.onEvent(bloc, event);
  }

  [@override](/user/override)
  void onTransition(IsolateBloc bloc, Transition transition) {
    print('New ${transition.nextState} from $bloc');
    super.onTransition(bloc, transition);
  }

  [@override](/user/override)
  void onError(IsolateBlocBase bloc, Object error, StackTrace stackTrace) {
    print('$error in $bloc');
    super.onError(bloc, error, stackTrace);
  }
}

更多关于Flutter隔离区数据管理插件isolate_bloc的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter隔离区数据管理插件isolate_bloc的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于isolate_bloc这个Flutter插件,它主要用于在Flutter应用中实现跨Isolate的数据管理,从而提高应用的性能和响应速度。以下是一个简单的代码示例,展示了如何使用isolate_bloc来管理跨Isolate的数据。

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

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

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

接下来,我们将创建一个简单的示例,其中包括一个Bloc来处理计算密集型任务,并在Isolate中运行这些任务。

1. 创建Bloc和Event

首先,定义一个简单的Event和一个State:

// counter_event.dart
import 'package:equatable/equatable.dart';

abstract class CounterEvent extends Equatable {
  const CounterEvent();
  
  @override
  List<Object?> get props => [];
}

class IncrementEvent extends CounterEvent {}
// counter_state.dart
import 'package:equatable/equatable.dart';

class CounterState extends Equatable {
  final int count;

  const CounterState({required this.count});

  @override
  List<Object?> get props => [count];
}

2. 创建Bloc

接下来,创建一个Bloc来处理这些Event,并在Isolate中执行计算:

// counter_bloc.dart
import 'dart:isolate';
import 'package:bloc/bloc.dart';
import 'package:isolate_bloc/isolate_bloc.dart';
import 'counter_event.dart';
import 'counter_state.dart';

class CounterBloc extends Bloc<CounterEvent, CounterState> with IsolateBloc {
  CounterBloc() : super(CounterState(count: 0)) {
    on<IncrementEvent>((event, emit) async {
      final result = await compute(increment, state.count);
      emit(CounterState(count: result));
    });
  }

  @override
  void onCreateIsolate(SendPort sendPort) {
    Isolate.spawn(isolateEntryPoint, sendPort);
  }

  static Future<int> increment(int count) async {
    // 模拟耗时操作
    await Future.delayed(const Duration(seconds: 2));
    return count + 1;
  }

  static void isolateEntryPoint(SendPort sendPort) {
    final receivePort = ReceivePort();
    sendPort.send(receivePort.sendPort);
    receivePort.listen((message) async {
      if (message is Map && message['type'] == 'compute') {
        final function = message['function'] as Function;
        final args = message['args'] as List;
        final result = await compute(function, ...args);
        sendPort.send({'result': result});
      }
    });
  }
}

注意:在实际应用中,increment函数应该被放在另一个文件中,并通过compute函数调用,以保持Isolate的纯净性。这里为了简化示例,直接在Bloc中定义了increment函数。

3. 使用BlocProvider和BlocBuilder

最后,在你的Flutter应用中使用BlocProviderBlocBuilder来提供和消费Bloc:

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_bloc.dart';
import 'counter_event.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Isolate Bloc Example')),
        body: Center(
          child: BlocProvider(
            create: (_) => CounterBloc(),
            child: CounterPage(),
          ),
        ),
      ),
    );
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<CounterBloc, CounterState>(
      builder: (context, state) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('You have pushed the button this many times:'),
            Text(
              '${state.count}',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        );
      },
    );
  }
}

class IncrementButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {
        context.read<CounterBloc>().add(IncrementEvent());
      },
      child: const Text('Increment'),
    );
  }
}

CounterPage中,你可以添加IncrementButton来触发IncrementEvent

// 修改CounterPage以包含IncrementButton
class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<CounterBloc, CounterState>(
      builder: (context, state) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('You have pushed the button this many times:'),
            Text(
              '${state.count}',
              style: Theme.of(context).textTheme.headline4,
            ),
            const SizedBox(height: 20),
            IncrementButton(), // 添加这个按钮
          ],
        );
      },
    );
  }
}

这个示例展示了如何使用isolate_bloc来在Isolate中处理耗时操作,并保持UI的响应性。请注意,实际应用中可能需要更复杂的错误处理和状态管理。

回到顶部