I have a puzzle game app. (https://play.google.com/store/apps/details?id=com.karolinadart.blackbox)
When the player thinks they have solved the puzzle, they press the "This is my final answer" button, at which point the score is calculated. A new screen is pushed, displaying the score.
But the score calculation is a rather heavy computation which can take several seconds, depending on the complexity of the particular setup. Therefore, I've made the score counting function async
and try to show a spinner while waiting for the computation to finish... but this doesn't work! I've tried starting the spinner a bit before the computation just to see if it starts... and it does, but the moment the computation starts, the spinner freezes.
How should I program it so that the heavy computation can go on in the background, while leaving the phone free to do other things, such as showing a spinner, or even continue with other tasks in the game?
These are the main features of the result displaying code:
import 'package:intl/intl.dart';
import 'package:blackbox/my_firebase_labels.dart';
import 'package:blackbox/units/small_widgets.dart';
import 'package:blackbox/firestore_lables.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:blackbox/board_grid.dart';
import 'package:blackbox/play.dart';
import 'package:blackbox/constants.dart';
import 'package:blackbox/atom_n_beam.dart';
import 'package:collection/collection.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:blackbox/game_hub_updates.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:provider/provider.dart';
class SentResultsScreen extends StatefulWidget {
SentResultsScreen({@required this.setupData, @required this.resultPlayerId});
final Map<String, dynamic> setupData;
final String resultPlayerId;
@override
_SentResultsScreenState createState() => _SentResultsScreenState(setupData, resultPlayerId);
}
class _SentResultsScreenState extends State<SentResultsScreen> {
_SentResultsScreenState(this.setupData, this.resultPlayerId);
final Map<String, dynamic> setupData;
final String resultPlayerId;
FirebaseFirestore firestoreObject = FirebaseFirestore.instance;
Play thisGame; // My own class, containing all the logic of the game
bool resultsReady = false;
String errorMsg = '';
int beamScore;
int atomScore;
int totalScore;
bool awaitingData = false;
List<dynamic> alternativeSolutions;
bool showSpinner = true;
@override
void initState() {
super.initState();
getGameData();
}
void getGameData() async {
await Future.delayed(Duration(milliseconds: 500)); // The spinner spins for this duration, then freezes
Map<String, dynamic> setupData = widget.setupData;
if (setupData == null) {
setState(() {
errorMsg = 'Document contains no data';
showSpinner = false;
});
} else {
thisGame = Play(setupData);
alternativeSolutions = await thisGame.getScore(); // This is the heavy calculation!
}
setState(() {
totalScore = thisGame.atomScore + thisGame.beamScore;
resultsReady = true;
showSpinner = false;
});
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('blackbox')),
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: Column(
children: <Widget>[
Expanded(
child: FittedBox(
fit: BoxFit.scaleDown,
child: Column(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('My score'),
Text(
'beam score: ${resultsReady ? '${thisGame.beamScore}' : '...'}',
),
Text(
'atom penalty: ${resultsReady ? '${thisGame.atomScore} ' : '...'}',
),
Text(
'total: $totalScore' // Will be null if results are not ready
),
],
),
),
),
alternativeSolutions != null
? Text(
'Multiple solutions exist!',
)
: SizedBox(),
],
),
),
),
],
),
),
);
}
}