I am running my app and getting the error:
"NoSuchMethodError: The Method '[ ]' was called on null. Receiver: null. Tried calling: ."
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import '../model/Lesson.dart';
class MobileModeScreen extends StatefulWidget {
@override
_MobileModeScreenState createState() => _MobileModeScreenState();
}
class _MobileModeScreenState extends State<MobileModeScreen> {
List<Lesson> _lesson;
@override
void initState() {
super.initState();
Future.delayed(Duration.zero,() {
getLessonFromJSON(context);
});
print("lessonDescription: ${_lesson[0].lessonTitle}");
}
Future<List<Lesson>> getLessonFromJSON(BuildContext context) async {
String jsonString = await DefaultAssetBundle.of(context).loadString("assets/lessons/lessons.json");
return await Future.delayed(Duration.zero,() {
List<dynamic> data = jsonDecode(jsonString);
List<Lesson> lesson = data.map( (f) => Lesson.fromJSON(f) ).toList();
_lesson = lesson;
print("lessonDescription: ${_lesson[0].lessonTitle}");
return _lesson;
});
}
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
appBar: AppBar(
title: Container(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
decoration: BoxDecoration(
color: Color(0xffFFFFFF),
border: Border.all(
color: Color(0xffF5ED02),
width: 3,
),
borderRadius: BorderRadius.circular(25.0),
),
child: Text("lessonDescription: ${_lesson[0].lessonTitle}",
style: TextStyle(
//fontFamily: "Uthmani",
color: Color(0xff225587),
),
),
),
centerTitle: true,
backgroundColor: Color(0xff7F3F96),
),
body: ListView(
padding: const EdgeInsets.fromLTRB(5, 15, 5, 5),
children: <Widget>[
],
),
backgroundColor: Color(0xffF0E4F2),
),
);
}
}
I'm not getting the error when I try to access the value from the getLessonFromJSON function, but outside of the function, it's not working at all.
The error I get:
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building Builder:
The method '[]' was called on null.
Receiver: null
Tried calling: [](0)
The relevant error-causing widget was:
MaterialApp file:///home/hmalabeh/AndroidStudioProjects/Flutter/Bounyan/boynyan_final/lib/main.dart:12:12
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 _MobileModeScreenState.initState (package:boynyanfinal/screens/mobile_mode_screen.dart:26:40)
#2 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4355:58)
#3 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4201:5)
#4 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3194:14)
...
Can someone help please.
Update:
I want to be able to use what I get from the function getLessonFromJSON in the build method like I'm using in the Text filed in the AppBar
Move the get data to a different function and await the response:
@override
void initState() {
super.initState();
load();
}
void load() async {
setState(() {
await getLessonFromJSON(context);
});
}
Also place a loader anywhere you're using _lesson, example in your Appbar:
var text = _lesson == null ? 'Loading...' : 'lessonDescription: ${_lesson[0].lessonTitle}';
Text(text,
style: TextStyle(
//fontFamily: "Uthmani",
color: Color(0xff225587),
),
)
_lesson is null because its value is assigned only when Future.delayed is resolved.
To solve it, either move print("lessonDescription: ${_lesson[0].lessonTitle}"); inside Future handler (after getLessonFromJSON(context);) or just remove that line at all because as far as I can suppose, it's needed only for debugging purposes.
This should work:
void initState() {
super.initState();
Future.delayed(Duration.zero,() {
getLessonFromJSON(context);
print("lessonDescription: ${_lesson[0].lessonTitle}");
});
}
You should initialize '_lesson' with an empty list
``` List _lesson = [];````
And then add item to this list in initState by using _lesson.add(item) and called setState to update the state of app.
This will work but you should FutureBuilder for async operations and use provider or bloc for better State management
I've added the setState() inside the getLessonFromJSON and I've added a loader in the places I use values from _lesson as @Sami suggested.
_lesson doesn't need to ve initialized.
@override
void initState() {
super.initState();
getLessonFromJSON(context);
}
Future<List<Lesson>> getLessonFromJSON(BuildContext context) async {
String jsonString = await DefaultAssetBundle.of(context).loadString("assets/lessons/lessons.json");
try{
return await Future.delayed(Duration.zero,() {
List<dynamic> data = jsonDecode(jsonString);
List<Lesson> lesson = data.map( (f) => Lesson.fromJSON(f) ).toList();
setState(() {
_lesson = List.from(lesson);
});
print("[getLessonFromJSON] lessonDescription: ${lesson[0].lessonTitle}");
return lesson;
});
} catch(e){
print(e);
}
}
The loader
_lessonTitle = _lesson == null ? 'Loading...' : _lesson[0].lessonTitle;
User contributions licensed under CC BY-SA 3.0