Reputation: 251
In my use case, I have to change the layout of the app with JSON data. I have a JSON file which I want to get and use the key values without using the Future method in the next method rather I want to place the mapped JSON and place it in empty curly brackets:
This is the JSON file I grab:
# test_json.json
{
"fontSize" : "10",
"fontFamily" : "A",
"fontWeigth" : "bold",
"fontColor" : "blue"
}
This is the file that grabs the JSON file and maps it:
# get_json.dart
class GetJson{
Future<Map<String, dynamic>> getJson() async {
String jsonData =
await rootBundle.loadString('assets/json/test_json.json');
Map<String, dynamic> data = jsonDecode(jsonData);
return data;
}
}
Then I grab this mapped JSON and I want to place it inside a variable called mappedData
and place it inside empty curly brackets. Then I want to get the number with getNumber()
and inside this method I convert the type of fontSize
from string to double with another custom method called TypeConvertor.getDouble()
:
class Utility {
var mappedData= {};
setJson() async {
mappedData = await GetJson().getJson();
}
getNumber(String key) {
var data = mappedData;
return TypeConvertor.getDouble(data[key]);
}
}
In my use case, i need to do this like this I have no other choice. I want to explicitly grab the JSON like that and I don't want getNumber()
to be a Future. Then i cannot place Utility().getNumber("fontSize")
inside a stateful widget because then I have to use setState
and I want to avoid that because I will have a lot of keys beside fontSize
and so then I have to use setState
for every key values. I just want to use Utility().getNumber("fontSize")
inside property fontSize
and The rest also like this. In my usecase I have to do it like that:
class TestView extends StatefulWidget {
const TestView({Key? key}) : super(key: key);
@override
State<TestView> createState() => _TestViewState();
}
class _TestViewState extends State<TestView> {
@override
Widget build(BuildContext context) {
return Text(
"test",
style: TextStyle(fontSize: Utility().getNumber("fontSize")),
);
}
}
But in my app mappedData
gives null. The full error is : Unhandled Exception: type 'Null' is not a subtype of type 'String'
and the null value is inside mappedData
. I want to grab the json data and place it inside an empty map and use the mapped json from there on. How do i resolve the null execption issue?
EDIT
Change variables to correct versions
Upvotes: 0
Views: 108
Reputation: 251
I found the solution which is partly contributed by @bakatsuyuki. So i did use await utility.setJson();
but i also initilized it with initState()
so field utility
has no null
value. I also used FutureBuilder()
to check if snapshot.hasData
and then i display the Text()
widget with the data from utilitiy
else show empty Container
. This way i can resolve the null
Exception.
This is the view that worked for me:
class AppView extends StatefulWidget {
const AppView({
Key? key,
}) : super(key: key);
@override
_AppViewState createState() => _AppViewState();
}
class _AppViewState extends State<AppView> {
final utility = Utility();
Future setUtility() async {
await utility.setJson();
}
@override
void initState() {
setUtility();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder(
future: AppContent().getAppContent(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text("test",
style: TextStyle(
fontSize: utility.getNumber("fontSize"),
));
} else {
return Container();
}
}),
),
);
}
}
Upvotes: 0
Reputation: 166
Probably it's because you don't call setJson
before call getNumber
.
The following code is work.
final utility = Utility();
await utility.setJson();
print(utility.getNumber("fontSize"));
If you want to avoid similar mistakes, you have some options as solutions.
mappedData
to Utility's constructor.getNumber
to static, and add argument mappedData
.Upvotes: 1