flutterdartsocketsandroid-contentprovidernull-safety

type 'Null' is not a subtype of type 'num' of 'other'


I'm developing a multiplayer sentence game using Flutter and ran into a problem with handling dynamic data coming from a server. Specifically, I'm encountering a TypeError related to null safety in Dart, and I'm having trouble identifying the source of the null value causing this issue. The error occurs when I try to access player information in my SentenceGame widget.

Code Snippet:

sentence_game.dart


class SentenceGame extends StatefulWidget {
  const SentenceGame({Key? key}) : super(key: key);

  @override
  State<SentenceGame> createState() => _SentenceGameState();
}

class _SentenceGameState extends State<SentenceGame> {
  var playerMe = null;
  final SocketMethods _socketMethods = SocketMethods();

  @override
  void initState() {
    super.initState();
    _socketMethods.updateGame(context);
  }

  findPlayerMe(GameStateProvider game) {
    game.gameState['players'].forEach((player) {
      if (player['socketID'] == SocketClient.instance.socket!.id) {
        playerMe = player;
      }
    });
  }

  Widget getTypedWords(words, player) {
    var tempWords = words.sublist(0, player['currentWordIndex']);
    String typedWord = tempWords.join(' ');
    return Text(
      typedWord,
      style: const TextStyle(
        color: Color.fromRGBO(52, 235, 119, 1),
        fontSize: 30,
      ),
    );
  }

  Widget getCurrentWord(words, player) {
    return Text(
      words[player['currentWordIndex']],
      style: const TextStyle(
        decoration: TextDecoration.underline,
        fontSize: 30,
      ),
    );
  }

  Widget getWordsToBeTyped(words, player) {
    var tempWords = words.sublist(player['currentWordIndex'] + 1, words.length);
    String wordstoBeTyped = tempWords.join(' ');
    return Text(
      wordstoBeTyped,
      style: const TextStyle(
        fontSize: 30,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final game = Provider.of<GameStateProvider>(context);
    findPlayerMe(game);

  if (game.gameState['words'].length > playerMe['currentWordIndex']) {
      return Padding(
        padding: const EdgeInsets.symmetric(
          horizontal: 20,
        ),
        child: Wrap(
          textDirection: TextDirection.ltr,
          children: [
            getTypedWords(game.gameState['words'], playerMe),
            getCurrentWord(game.gameState['words'], playerMe),
            getWordsToBeTyped(game.gameState['words'], playerMe),
          ],
        ),
      );
    }
    return const Scaffold();
  }
}

Error Message:

Exception caught by widgets library ═══════════════════════════════════ 
The following _TypeError was thrown building SentenceGame(dirty, dependencies: [_InheritedProviderScope<GameStateProvider?>], state: _SentenceGameState#2ae6e): type 'Null' is not a subtype of type 'num' of 'other'

The relevant error-causing widget was SentenceGame

What I've Tried:

Questions:

I appreciate any guidance or suggestions on how to resolve this issue.


Solution

  • Your playerMe variable could be null, but you don't check it for null while using in your code.

    Your should add null checks. Like that (it's your code without any refactoring, although it needs some, only null checks added):

    @override
      Widget build(BuildContext context) {
        final game = Provider.of<GameStateProvider>(context);
        findPlayerMe(game);
    
      if (playerMe != null && playerMe['currentWordIndex'] != null && game.gameState['words'].length > playerMe['currentWordIndex']) {
          return Padding(
            padding: const EdgeInsets.symmetric(
              horizontal: 20,
            ),
            child: Wrap(
              textDirection: TextDirection.ltr,
              children: [
                getTypedWords(game.gameState['words'], playerMe),
                getCurrentWord(game.gameState['words'], playerMe),
                getWordsToBeTyped(game.gameState['words'], playerMe),
              ],
            ),
          );
        }
        return const Scaffold();
      }
    

    And also it is recommendable here too:

    Widget getTypedWords(words, player) {
    if (player != null && player['currentWordIndex'] != null) {
        var tempWords = words.sublist(0, player['currentWordIndex']);
        String typedWord = tempWords.join(' ');
        return Text(
          typedWord,
          style: const TextStyle(
            color: Color.fromRGBO(52, 235, 119, 1),
            fontSize: 30,
          ),
        );
       } else {
        return const SizedBox();
       }
      }
    
      Widget getCurrentWord(words, player) {
        if (player != null && player['currentWordIndex'] != null) {
         return Text(
            words[player['currentWordIndex']],
            style: const TextStyle(
            decoration: TextDecoration.underline,
            fontSize: 30,
          ),
        );
        } else {
         return const SizedBox();
        }
      }
    
      Widget getWordsToBeTyped(words, player) {
    if (player != null && player['currentWordIndex'] != null) {
        var tempWords = words.sublist(player['currentWordIndex'] + 1, words.length);
        String wordstoBeTyped = tempWords.join(' ');
         return Text(
           wordstoBeTyped,
           style: const TextStyle(
             fontSize: 30,
           ),
         );
        } else {
         return const SizedBox();
        }
      }
    

    That should work. But I also strongly recommend you doing some code refactoring.