-1

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:

  • I checked for null values in the gameState['players'] list and ensured that the data received from the server is correct and not missing any expected fields.
  • I added null checks before accessing player['socketID'] and player['currentWordIndex'], but the error persists.

Questions:

  • How can I identify the exact source of the null value causing this TypeError?
  • What are the best practices for handling null safety in this scenario, especially when dealing with dynamic data from a server?
  • Is there a more efficient way to ensure that playerMe is not null before attempting to access its properties?

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

4
  • 1
    Null is not a Number .. simple as that ... You are expecting a result .. but that one did not have anything and returned NULL instead .. which is not numerical. Normally you test for null before you test for number to catch these. Commented Feb 28, 2023 at 17:21
  • Hello @easleyfixed, can you please show me how to edit the code? Commented Feb 28, 2023 at 17:25
  • The answer is found here --> flutterigniter.com/checking-null-aware-operators-dart Commented Feb 28, 2023 at 18:27
  • if (value != null) { doSomething(); } This is the basic format of a null check. Commented Feb 28, 2023 at 18:28

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.