title: flutter bloc and how a bloc state change can then trigger a 2nd async call before updating the Widget/UI with both? (code attached)
body: <p>How would one load a set of local images for display in a widget (noting this is async - see function below) triggered by (based on) a change in state from a flutter_bloc for “settings”?  Noting this bloc is persisted too via hydrated_bloc.  So the use case for which I’m asking how do I code this in flutter (noting I’m using flutter_bloc) is:</p>
  <p>Use Case - Render different set of images on the same Widget I have for dynamically displaying a room for a 2D point &amp; click adventure type game, BASED ON the “room” the user goes to.  A change in room event is passed to a SettingsBloc which will then determine the new “room” to move to.  This new “room” state is available via the Bloc concept, however how &amp; where do I then do the async load of the specific set of images I need for this room (nothing they are set at compile time)?  (To feed it to the dynamic room rendering widget with a CustomPainter that I have - i.e. images painted onto canvas).</p>
  <p>For example which approach is recommended to do this? (then ideally what the code looks like to achive this)</p>
  <p>a) Listen for a change in “room” within the widget, and then trigger (within a widget) to call the async function to dynamically load the  ui.Image’s that I need?  But if yes, how do you do this in code within a Widget? (or is this not best practice). Refer my code below which does work/run but seems to have a infinite loop happening  OR</p>
  <p>b) Should I setup Images as a separate bloc (e.g. images_bloc).  But in this case what is the flutter code that would be required to do this:  i.e.</p>
  <ul>
  <li>user does something in UI that triggers an event &amp; passes it to SettingsBloc</li>
  <li>the SettingsBloc then may determine there is a change in &quot;room&quot; due to this and change/emit the new &quot;currentRoom&quot;</li>
  <li>the SettingsBloc would then then to trigger an aynch request to ImagesBlock (somehow) get the new List of ui.Images for this &quot;room&quot;, using the async code below</li>
  <li>The UI/Widget then needs to pickup the changes for “String room” and List of ui.Image’s</li>
  </ul>
  <p>c) Another approach?</p>
  <hr />
  <p>Here is my best try at approach (a) above so far.  Works in UI re changing background, however there seems to be an infinite loop:</p>
  <p>Logging:</p>
  <pre><code>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
  </code></pre>
  <p>Code:</p>
  <pre><code>import 'dart:async';
  import 'dart:typed_data';
  import 'dart:ui' as ui;
  import 'package:adventure/ui/widgets/game_painter.dart';
  import 'package:flutter/services.dart';
  import 'package:flutter_bloc/flutter_bloc.dart';
  import 'package:adventure/bloc/settings_cubit.dart';
  import 'package:adventure/game_design/room.dart';
  import 'package:flutter/material.dart';
  import 'package:touchable/touchable.dart';
  
  class GameMain extends StatefulWidget {
    GameMain({Key key}) : super(key: key);
    @override
    _GameMainState createState() =&gt; _GameMainState();
  }
  
  class _GameMainState extends State&lt;GameMain&gt; {
    final RoomsData roomsData = RoomsData.getPopulated();
    ui.Image _backgroundImage;
  
    Future&lt;ui.Image&gt; _loadImageAsync(imageString) async {
      ByteData bd = await rootBundle.load(imageString);
      final Uint8List bytes = Uint8List.view(bd.buffer);
      final ui.Codec codec = await ui.instantiateImageCodec(bytes);
      final ui.Image image = (await codec.getNextFrame()).image;
      return image;
    }
  
    Future&lt;void&gt; _updateBackgroundImageState(String imagename) async {
      print('About to load imagename:$imagename');
      final image = await _loadImageAsync('assets/images/$imagename');
      setState(() {
        _backgroundImage = image;
      });
    }
  
    @override
    Widget build(BuildContext context) {
      print('game_main.build ----------------------------');
  
      // Get Persistant Data Settings 
      SettingsCubit settingsCubit = context.watch&lt;SettingsCubit&gt;();
  
      // Get Room Configuration (for room we're now in)
      print('Trying to get room data for current room: ${settingsCubit.state.currentRoom}');
      Room roomData = roomsData.getRoom(settingsCubit.state.currentRoom);
  
      // Update Background Image
      _updateBackgroundImageState(roomData.backgroundImage);
      
      // Create and return Canvas
      return Container(
        child: BlocBuilder&lt;SettingsCubit, SettingsState&gt;(
          builder: (context, state) {
            return Stack(children: &lt;Widget&gt;[
  
              CanvasTouchDetector(
                builder: (context) =&gt; CustomPaint(
                  painter: GamePainter(context, settingsCubit, roomData, _backgroundImage)
                )
              ),
  
              FlatButton(
                // For testing changes to background image
                color: Colors.blue,
                textColor: Colors.white,
                onPressed: () {
                  var newRoomString = settingsCubit.state.currentRoom == 'room1' ? 'room2' : 'room1';
                  settingsCubit.setRoom(newRoomString);
                },
                child: Text(
                  &quot;Flat Button&quot;,
                  style: TextStyle(fontSize: 20.0),
                ),
              ),
  
            ]);
          }
        )
      );
  
    }
  }
  </code></pre>