Scenario: I have a page with a ListView which shows a list of several items from the database, fetched using a REST API. I am loading the data in the initState() method. In order to load the data, I also need some data stored in the Shared Preferences. I obtain the instance of shared preferences before loading the data and rendering the UI. The UI changes based on the AccountType stored in the Shared Preferences.
Problem: When I navigate to the specific page in the app, I get an error-
LateInitializationError: Field '_sharedPreferences@53458703' has not been initialized.
The relevant error-causing widget was:
QuizListPage QuizListPage:file:///D:/Github_Work/Assessment%20Portal/assessmentportal/lib/Pages/CategoryTile.dart:27:41
When the exception was thrown, this was the stack:
#0 _QuizListPageState._sharedPreferences (package:assessmentportal/Pages/QuizListPage.dart)
#1 _QuizListPageState.build (package:assessmentportal/Pages/QuizListPage.dart:72:19)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4992:27)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4878:15)
#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#5 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#6 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4859:5)
#7 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5041:11)
#8 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4853:5)
... Normal element mounting (275 frames)
My code is-
class QuizListPage extends StatefulWidget {
CategoryModel category;
QuizListPage({required this.category});
@override
State<QuizListPage> createState() => _QuizListPageState();
}
class _QuizListPageState extends State<QuizListPage> {
late SharedPreferences _sharedPreferences;
List<QuizModel> quizzes = [];
late CategoryService _categoryService;
bool _areQuizzesLoaded = false;
@override
void initState() {
super.initState();
_initializeData();
}
void _initializeData() async {
_sharedPreferences = await SharedPreferences.getInstance();
_categoryService = CategoryService();
setState(() {
_areQuizzesLoaded = false;
});
await _loadCategories();
}
Future<void> _loadCategories() async {
if (_sharedPreferences.getString(ROLE) == ROLE_NORMAL) {
quizzes = await _categoryService.getAllQuizzesByCategory(
_sharedPreferences.getString(BEARER_TOKEN) ?? 'null',
widget.category.categoryId);
} else {
quizzes = await _categoryService.getAllQuizzesByAdminAndCategory(
adminid: _sharedPreferences.getInt(USER_ID) ?? 0,
categoryid: widget.category.categoryId,
token: _sharedPreferences.getString(BEARER_TOKEN) ?? 'null',
);
}
setState(() {
log('Setting loaded to true');
_areQuizzesLoaded = true;
});
}
@override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height -
AppBar().preferredSize.height -
MediaQuery.of(context).padding.top -
MediaQuery.of(context).padding.bottom;
final width = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
title: Text(widget.category.categoryTitle),
actions: (_sharedPreferences.getString(ROLE) != ROLE_NORMAL)
? [
Container(
margin: const EdgeInsets.only(
top: 10,
right: 10,
left: 5,
bottom: 5,
),
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddQuizPage(
userid: _sharedPreferences.getInt(USER_ID) ?? 0,
categoryid: widget.category.categoryId ?? 0,
token: _sharedPreferences.getString(BEARER_TOKEN) ??
'null',
),
),
);
},
child: const Text('Add Quiz'),
),
),
]
: null,
),
body: Container(
child:Text('Hello'),
),
);
}
}
Please help me understand why this error occurs (sometimes not always) and what is the correct way to load data before showing the UI (Some UI components depend on the data stored in shared preferences), I want to use Shared Preferences, the way its used in my code. Please help!