Flutter Flatter bloc以及bloc状态更改如何在使用这两者更新小部件/UI之前触发第二次异步调用?(附代码)

Flutter Flatter bloc以及bloc状态更改如何在使用这两者更新小部件/UI之前触发第二次异步调用?(附代码),flutter,dart,flutter-bloc,dart-async,Flutter,Dart,Flutter Bloc,Dart Async,如何加载一组本地图像以在小部件中显示(注意这是异步的-请参见下面的函数),该小部件由“设置”的颤振块的状态变化触发(基于该变化)?注意,这个团也通过水合团持续存在。因此,我要问的用例是如何在flatter(注意我使用的是flatter_bloc)中对其进行编码: 用例-在同一个小部件上呈现不同的图像集,根据用户去的“房间”动态显示2D点击冒险类型游戏的房间。房间变更事件被传递给SettingsBloc,然后该SettingsBloc将确定要移动到的新“房间”。这个新的“房间”状态是通过Bloc概

如何加载一组本地图像以在小部件中显示(注意这是异步的-请参见下面的函数),该小部件由“设置”的颤振块的状态变化触发(基于该变化)?注意,这个团也通过水合团持续存在。因此,我要问的用例是如何在flatter(注意我使用的是flatter_bloc)中对其进行编码:

用例-在同一个小部件上呈现不同的图像集,根据用户去的“房间”动态显示2D点击冒险类型游戏的房间。房间变更事件被传递给SettingsBloc,然后该SettingsBloc将确定要移动到的新“房间”。这个新的“房间”状态是通过Bloc概念提供的,但是我如何&在哪里异步加载这个房间所需的特定图像集(编译时没有设置)?(使用我拥有的CustomPainter(即绘制到画布上的图像)将其提供给dynamic room rendering小部件)

例如,建议采用哪种方法进行此操作?(理想情况下,实现这一点的代码是什么样子的)

a) 监听小部件中“房间”的变化,然后触发(在小部件中)调用异步函数来动态加载ui?但如果是,您如何在小部件中的代码中实现这一点?(或者这不是最佳实践)。请参阅下面我的代码,它确实工作/运行,但似乎有一个无限循环正在发生或正在运行

b) 我是否应将图像设置为单独的组(例如图像组)。但在这种情况下,需要什么样的颤振代码来实现这一点:即

  • 用户在UI中执行某些操作来触发事件并将其传递给SettingsBloc
  • 然后,设置SBLOC可确定“房间”因此发生变化,并改变/发出新的“currentRoom”
  • 然后,setingsbloc将触发一个aynch请求,以便ImagesBlock(以某种方式)使用下面的异步代码获取此“房间”的新ui.Images列表
  • 然后,UI/小部件需要获取“字符串室”和UI.Image的列表的更改
c) 另一种方法


这是我迄今为止对上述方法(a)的最佳尝试。在UI重新更改背景中工作,但似乎存在无限循环:

日志记录:

Launching lib/main.dart on iPhone 12 Pro Max in debug mode...
lib/main.dart:1
Xcode build done.                                           29.5s
Connecting to VM Service at ws://127.0.0.1:49364/lyUIDblZgmY=/ws
flutter: game_main.build ----------------------------
flutter: trying to get room data for current room: room2
flutter: About to load imagename:plane.png
flutter: game_main.build ----------------------------
flutter: trying to get room data for current room: room2
flutter: About to load imagename:plane.png
flutter: game_main.build ----------------------------
flutter: trying to get room data for current room: room2
flutter: About to load imagename:plane.png
flutter: game_main.build ----------------------------
ETC ETC
代码:

导入'dart:async';
导入“dart:键入的_数据”;
将“dart:ui”导入为ui;
导入“包:冒险/ui/widgets/game_painter.dart”;
导入“包:flifter/services.dart”;
进口“包装:颤振团/颤振团.飞镖”;
导入“package:adventure/bloc/settings_cubit.dart”;
导入“套装:冒险/游戏设计/房间.飞镖”;
进口“包装:颤振/材料.省道”;
导入“package:touchable/touchable.dart”;
类GameMain扩展了StatefulWidget{
GameMain({Key}):super(Key:Key);
@凌驾
_GameMostate createState()=>\u GameMostate();
}
类\u GameMostate扩展状态{
final RoomsData RoomsData=RoomsData.getPopulated();
ui.Image\u背景图像;
Future\u loadImageAsync(imageString)异步{
ByteData bd=等待rootBundle.load(imageString);
最终Uint8List字节=Uint8List.view(bd.buffer);
final ui.Codec Codec=wait ui.instantialeimagecodec(字节);
final ui.Image Image=(wait codec.getNextFrame()).Image;
返回图像;
}
Future\u updateBackgroundImageState(字符串imagename)异步{
打印(‘即将加载imagename:$imagename’);
final image=await_loadImageAsync('assets/images/$imagename');
设置状态(){
_背景图像=图像;
});
}
@凌驾
小部件构建(构建上下文){
打印('game_main.build--------------------');
//获取持久数据设置
setingscubit setingscubit=context.watch();
//获取房间配置(对于我们现在所在的房间)
print('尝试获取当前文件室的文件室数据:${settingsCubit.state.currentRoom}');
Room roomData=roomsData.getRoom(设置scubit.state.currentRoom);
//更新背景图像
_updateBackgroundImageState(roomData.backgroundImage);
//创建并返回画布
返回容器(
孩子:BlocBuilder(
生成器:(上下文、状态){
返回堆栈(子级:[
CanvasTouchDetector(
生成器:(上下文)=>CustomPaint(
画师:游戏画师(上下文、设置位、房间数据、背景图像)
)
),
扁平按钮(
//用于测试对背景图像的更改
颜色:颜色,蓝色,
textColor:Colors.white,
已按下:(){
var newRoomString=settingsCubit.state.currentRoom=='room1'?'room2':'room1';
setingscubit.setRoom(newRoomString);
},
子:文本(
“扁平按钮”,
样式:TextStyle(fontSize:20.0),
),
),
]);
}
)
);
}
}

您的代码的问题是您将设置状态放在构建中,因此它称为build->\u updateBackgroundImage->setStatus->rebuild->\u updateBackgroundImage。。。(无限)

我认为日期更新流程如下所示:

change SettingsCubit -> get RoomData ->  (wait for async image data) -> _updateBackgroundImage
问题是,如果图像仍在加载中,您希望显示什么? 答案可能是:

  • 更改背景/房间,直到加载图像
  • 显示加载指示器
  • 先显示同步数据,然后更改背景
  • 最后两个可以很容易地完成。但对于bloc概念,您可以在设置位中添加新状态,并在加载时控制图像状态

    class SettingsCubit extends Cubit{
      ...
      Future setRoom(String newRoom) async {
        // emit state (imageIsLoading = true)
        // load image async func
        // emit state (imageIsLoading = false, image data update in state)
      }
    }
    ...
    
    @override
    Widget build(BuildContext context) {
      SettingsCubit settingsCubit = context.watch<SettingsCubit>();
    
      if(settingsCubit.state.imageIsLoading){
        // show what do you want to show when image is not ready
      }else{
        // show room with image (ex. from settingsCubit.state.imageData)
      }
    
    类设置位扩展了Cubit{
    ...
    未来设置室(字符串newRoom)异步{
    //发射状态(imageIsLoading=true)
    //加载图像异步函数
    //发射状态(imageIsLoading=false,图像数据更新处于状态)
    }
    }
    ...
    @凌驾
    威奇
    
    class SettingsCubit extends Cubit{
      ...
      Future setRoom(String newRoom) async {
        // emit state (imageIsLoading = true)
        // load image async func
        // emit state (imageIsLoading = false, image data update in state)
      }
    }
    ...
    
    @override
    Widget build(BuildContext context) {
      SettingsCubit settingsCubit = context.watch<SettingsCubit>();
    
      if(settingsCubit.state.imageIsLoading){
        // show what do you want to show when image is not ready
      }else{
        // show room with image (ex. from settingsCubit.state.imageData)
      }