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