Solved: Flutter App is freezing after few button press

Question

Asked by Shakun's on December 15, 2021 (source).

I'm building a While of Fortune with the help of the flutter_fortune_wheel package. The value where the wheel stops are predecided as the animation starts. I'm generating a random number between 0 - 9 and to avoid the number 1 & 8 I'm using a while loop. But after a few spins the app freezes. I think while loops are the reason because when I comment while loop the app doesn't freeze. I'm not 100% sure

/// Instances
final _shopController = Get.find<ShopController>();

class WheelOfFortune extends StatefulWidget {
  @override
  _WheelOfFortuneState createState() => _WheelOfFortuneState();
}

class _WheelOfFortuneState extends State<WheelOfFortune> {
  //
  StreamController<int> _controller = StreamController<int>();

  // Spins Available
  int _availableSpins = 10;

  // SelectedIndex
  int _winningIndex = 0;

  // Disable Spin Button
  bool _disableSpinButton = false;

  // Reward Value List
  final _rewardList = [
    // #0 1k FC
    {
      'prize': 'FC',
      'value': 1000,
    },

    // #1 100 GB JACKPOT
    {
      'prize': 'GB',
      'value': 100,
    },

    // #2 1k FC
    {
      'prize': 'FC',
      'value': 5000,
    },

    // #3 2 GB
    {
      'prize': 'GB',
      'value': 2,
    },

    // #4 1 SPIN
    {
      'prize': 'Spin',
      'value': 1,
    },

    // #5 15k FC
    {
      'prize': 'FC',
      'value': 15000,
    },

    // #6 AVOCADO
    {
      'prize': 'Avocado',
      'value': 1000,
    },

    // #7 10 GB
    {
      'prize': 'GB',
      'value': 10,
    },

    // #8 100k FC JACKPOT
    {
      'prize': 'FC',
      'value': 100000,
    },

    // #9 5 GB
    {
      'prize': 'GB',
      'value': 5,
    },
  ];

  //
  @override
  void dispose() {
    _controller.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 300.0,
      color: Colors.grey.shade200,
      child: Column(
        children: [
          // Fortune Wheel
          Expanded(
            child: FortuneWheel(
              selected: _controller.stream,
              animateFirst: false,
              onAnimationStart: () {
                //
                int value = Random().nextInt(9);
                //
                do {
                  _controller.add(value);
                } while (value == 1 || value == 8);

                //
                setState(() {
                  _winningIndex = value;
                  _disableSpinButton = true;
                });

                print('This is WI $_winningIndex');
              },
              onAnimationEnd: () {
                final _priceName =
                    _rewardList[_winningIndex]['prize'].toString();
                final _priceValue =
                    _rewardList[_winningIndex]['value'].hashCode;
                //
                wofRewardDialogFN(
                  priceName: _priceName,
                  priceValue: _priceValue.hashCode,
                  context: context,
                );

                //
                if (_priceName == 'FC') {
                  _shopController.updateFootCoinsFN(fc: _priceValue);
                } else if (_priceName == 'GB') {
                  _shopController.updateGoldenBallsFN(gb: _priceValue);
                } else if (_priceName == 'Spin') {
                  setState(() {
                    _availableSpins = _availableSpins + 1;
                  });
                } else {
                  print('Avocado');
                }

                //
                setState(() {
                  _disableSpinButton = false;
                });
              },
              indicators: [
                FortuneIndicator(
                  alignment: Alignment.center,
                  child: TriangleIndicator(color: Colors.white),
                ),
              ],
              items: [
                // #0 15k FC
                FortuneItem(
                  child: WheelStrips(
                    svgImage: 'assets/images/footcoin.svg',
                    prizeText: ' 15k',
                  ),
                  style: FortuneItemStyle(
                    color: Colors.purpleAccent,
                    borderColor: Colors.black38,
                  ),
                ),

                // #6 Avocado
                FortuneItem(
                  child: WheelStrips(
                    svgImage: '',
                    prizeText: '   🥑',
                  ),
                  style: FortuneItemStyle(
                    color: Colors.red.shade300,
                    borderColor: Colors.black38,
                  ),
                ),

                // #1 10 GB
                FortuneItem(
                  child: WheelStrips(
                    svgImage: 'assets/images/goldenball.svg',
                    prizeText: ' 10',
                  ),
                  style: FortuneItemStyle(
                    color: Colors.redAccent,
                    borderColor: Colors.black38,
                  ),
                ),

                // #2 100k FC
                FortuneItem(
                  child: WheelStrips(
                    svgImage: 'assets/images/footcoin.svg',
                    prizeText: ' 100k',
                  ),
                  style: FortuneItemStyle(
                    color: Colors.lightGreen,
                    borderColor: Colors.black38,
                  ),
                ),

                // #3 5 GB
                FortuneItem(
                  child: WheelStrips(
                    svgImage: 'assets/images/goldenball.svg',
                    prizeText: '  5',
                  ),
                  style: FortuneItemStyle(
                    color: Colors.blue,
                    borderColor: Colors.black38,
                  ),
                ),

                // #4 1k coins
                FortuneItem(
                  child: WheelStrips(
                    svgImage: 'assets/images/footcoin.svg',
                    prizeText: ' 1k',
                  ),
                  style: FortuneItemStyle(
                    color: Colors.yellow.shade600,
                    borderColor: Colors.black38,
                  ),
                ),
                //

                // #5 100 GB
                FortuneItem(
                  child: WheelStrips(
                    svgImage: 'assets/images/goldenball.svg',
                    prizeText: '  100',
                  ),
                  style: FortuneItemStyle(
                    color: Colors.orange,
                    borderColor: Colors.black38,
                  ),
                ),

                // #7 5k FC
                FortuneItem(
                  child: WheelStrips(
                    svgImage: 'assets/images/footcoin.svg',
                    prizeText: ' 5k',
                  ),
                  style: FortuneItemStyle(
                    color: Colors.teal,
                    borderColor: Colors.black38,
                  ),
                ),

                // #8 2 GB
                FortuneItem(
                  child: WheelStrips(
                    svgImage: 'assets/images/goldenball.svg',
                    prizeText: '  2',
                  ),
                  style: FortuneItemStyle(
                    color: Colors.pink.shade200,
                    borderColor: Colors.black38,
                  ),
                ),

                // #9 1 Spin
                FortuneItem(
                  child: WheelStrips(
                    svgImage: '',
                    prizeText: '  1 Spin',
                  ),
                  style: FortuneItemStyle(
                    color: Colors.blue.shade700,
                    borderColor: Colors.black38,
                  ),
                ),
              ],
            ),
          ),

          // Spin Buttons
          GestureDetector(
            onTap: () {
              _disableSpinButton
                  ? null
                  : setState(() {
                      _availableSpins = _availableSpins - 1;
                      //
                      _availableSpins < 0
                          ? null
                          : _controller.add(
                              _winningIndex,
                            );
                    });
            },
            child: Chip(
              backgroundColor: _disableSpinButton ? Colors.grey : Colors.yellow,
              label: Text(
                  _availableSpins <= 0 ? '0 Spin' : '$_availableSpins Spins'),
              avatar: Icon(Icons.rotate_right_outlined),
            ),
          ),
        ],
      ),
    );
  }
}

class WheelStrips extends StatelessWidget {
  final String svgImage, prizeText;

  WheelStrips({required this.svgImage, required this.prizeText});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(right: 20.0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          // FootCoin SVG
          SvgPicture.asset(
            svgImage,
            height: 23.0,
          ),

          // FootCoins Text
          Text(
            prizeText,
            style: TextStyle(
              fontSize: 22.0,
              fontWeight: FontWeight.bold,
              fontFamily: 'NewYork',
            ),
          ),
        ],
      ),
    );
  }
}

Answer

Question answered by quoci (source).

The reason why you app is freezing is because if you get the number 1 or 8 your code is stuck in the while loop since you never change value again. To fix your issue you have to change value after you hit the number 1 or 8.

final random = Random();
int value = random.nextInt(9);
while(value == 1 || value == 8){
  // Assign new value everytime you hit 1 or 9
  value = random.nextInt(9);
}
_controller.add(value);

DART FLUTTER
SHARE: