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:
gameState['players']
list and ensured that the data received from the server is correct and not missing any expected fields.player['socketID']
and player['currentWordIndex']
, but the error persists.Questions:
TypeError
?playerMe
is not null before attempting to access its properties?I appreciate any guidance or suggestions on how to resolve this issue.
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.