在flutter中使用Chopper网络库和flutter_bloc库

Posted

技术标签:

【中文标题】在flutter中使用Chopper网络库和flutter_bloc库【英文标题】:Using Chopper networking library with flutter_bloc library in flutter 【发布时间】:2021-02-06 21:44:44 【问题描述】:

我正在使用 Chopper 库为我的业务逻辑调用 Rest API 和 flutter_bloc。

我的菜刀班

import 'package:chopper/chopper.dart';
import '../model/statement_res.dart';
import 'model_converter.dart';

part 'statement_api_service.chopper.dart';

@ChopperApi()
abstract class StatementApiService extends ChopperService 
  // 6
  @Get(
      path: 'getStatement')
  Future<Response<StatementRes>> getStatement(
    @Query() String AccountNo,
    @Query() String StartDate,
    @Query() String EndDate,
  );

  // 8
  static StatementApiService create() 
    // 9
    final client = ChopperClient(
      // 10
      baseUrl: 'SERVER_URL',
      interceptors: [HttpLoggingInterceptor()],
      converter: ModelConverter(),
      errorConverter: JsonConverter(),
      // 11
      services: [
        _$StatementApiService(),
      ],
    );
    // 12
    return _$StatementApiService(client);
  



我的模型类... Future 就像

class StatementRes 
  @JsonKey(name: 'StatusCode')
  String statusCode;
  @JsonKey(name: 'Desc')
  String desc;
  @JsonKey(name: 'Body')
  Body body; //Nested model class

事件类代码:


import 'package:equatable/equatable.dart';

abstract class StatementEvent extends Equatable 
  const StatementEvent();


class GetStatement extends StatementEvent 
  final String accountNo;
  final startDate;
  final endDate;

  const GetStatement(this.accountNo, this.startDate, this.endDate);

  @override
  List<Object> get props => [accountNo, startDate, endDate];


状态类代码:

import 'package:equatable/equatable.dart';
import '../model/statement_res.dart';
import 'package:chopper/chopper.dart';

abstract class StatementState extends Equatable 
  const StatementState();


class StatementInitial extends StatementState 
  const StatementInitial();
  @override
  List<Object> get props => [];


class StatementLoading extends StatementState 
  const StatementLoading();
  @override
  List<Object> get props => [];


class StatementLoaded extends StatementState 
  final Response<StatementRes> statementRes;
  const StatementLoaded(this.statementRes);
  @override
  List<Object> get props => [statementRes];


class StatementError extends StatementState 
  final String message;
  const StatementError(this.message);
  @override
  List<Object> get props => [message];


这是我的 Bloc(mapEventToState) 代码

import 'dart:async';
import 'package:bloc/bloc.dart';
import '../service/statement_api_service.dart';
import './bloc.dart';

class StatementBloc
    extends Bloc<StatementEvent, StatementState> 
  StatementBloc(StatementState initialState) : super(initialState);

  @override
  StatementState get initialState => StatementInitial();

  @override
  Stream<StatementState> mapEventToState(
    StatementEvent event,
  ) async* 
    yield StatementLoading();
    if (event is GetStatement) 
      try 
        final statementResponse =
            await StatementApiService.create()
                .getStatement(
                    AccountNo: event.accountNo,
                    StartDate: event.startDate,
                    EndDate: event.endDate);
        yield StatementLoaded(statementResponse);
       catch (e) 
        yield StatementError("Failed to fetch Statement");
      
    
  


我正在尝试从我的 UI 中调用 Bloc 的代码,如下所示:

class MyHomePage extends StatefulWidget 
  final String title;

  MyHomePage(Key key, this.title) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State<MyHomePage> 
  StatementBloc stmtBloc;

  @override
  void initState() 
    super.initState();
    stmtBloc = StatementBloc(StatementInitial());
  

  @override
  void didChangeDependencies() 
    super.didChangeDependencies();

    stmtBloc.add(
        GetStatement("1155328002", "09-OCT-2020", "19-OCT-2020"));
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text("Testing - Bloc"),
      ),
      body: Container(
        padding: EdgeInsets.symmetric(vertical: 16),
        alignment: Alignment.center,
        child:
          BlocBuilder<StatementBloc, StatementState>(
          builder: (context, state) 
            if (state is StatementLoading) 
              print("#################");
              print("**********StatementLoading*************");
              print("#################");

              return buildLoading();
           else if (state is StatementLoaded) 
              print("#################");
 ,print("**********StatementLoaded*************");
              print("#################");

              return buildColumnWithData(
                  context, state.sStatementRes.body.responseDesc);
             else 
              print("#################");
              print("**********Else*************");
              print("#################");

              return buildLoading();
            
          ,
        ),
      ),
    );
  


我能够成功调用 API 并能够获得响应。但无法在 UI 中显示。收到以下异常:

flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following assertion was thrown building Container(center, padding: EdgeInsets(0.0, 16.0, 0.0,
flutter: 16.0)):                                                        
flutter:         BlocProvider.of() called with a context that does not contain a Cubit of type
flutter: StatementBloc.                                     
flutter:         No ancestor could be found starting from the context that was passed to
flutter: BlocProvider.of<StatementBloc>().                  
flutter:                                                                
flutter:         This can happen if the context you used comes from a widget above the BlocProvider.
flutter:                                                                
flutter:         The context used was: BlocBuilder<StatementBloc,
flutter: StatementState>(dirty, state: _BlocBuilderBaseState<StatementBloc,
flutter: StatementState>#4c48e(lifecycle state: created))   
flutter:                                                                
flutter:                                                                
flutter: The relevant error-causing widget was:                         
flutter:   Container                                                    
flutter:   file:/lib/views/my_home_page.dart:50:13

请指导我如何解决上述问题。

【问题讨论】:

【参考方案1】:

我认为最好将“BlocBuilder”用作“BlocProvider”的子级,如下所示:

BlocProvider(
     create: (context) => StatementBloc()..add(Fetch()),
     child: BlocBuilder<StatementBloc, StatementState>(
          builder: (mContext, state) 
               // your code
          
     ),
),

并从 'initState()' 中删除这一行:

stmtBloc = StatementBloc(StatementInitial());

我希望这行得通。

【讨论】:

谢谢,您的回答帮助我解决了这个问题。

以上是关于在flutter中使用Chopper网络库和flutter_bloc库的主要内容,如果未能解决你的问题,请参考以下文章

Dart Flutter - 使用 Chopper 获取 WordPress 自定义帖子类型

Flutter 安装配置和初步使用记录

在颤振中使用 MVP 架构的 Chopper

在颤动中使用 Chopper 库将 JSON 响应转换为模型对象?

为啥 Flutter 中的 BloCListener 不保存状态,认证过程中出现 setState() 问题?

在 Flutter 中使用完整的 Dart SDK