68
votes

How do I load a JSON asset into my Flutter app?

My pubspec.yaml file has the following:

  assets:
    - assets/data.json

I keep getting stuck trying to load the data. I tried

final json = JSON.decode(
    DefaultAssetBundle.of(context).loadString("assets/data.json")
);

But I get the error

The argument type 'Future< String>' can't be assigned to the parameter type 'String'.

Thanks!

4
Apparently JSON.Decode returns a map, not a string - Alexandre Beaudet
Yes, the end result I want is a map from JSON.decode. I'm just having trouble feeding it the string representation of the JSON file. - nalyd88

4 Answers

35
votes

@Alexandre Beaudet's answer is correct but doesn't give a lot of context about what is going on.

When you're calling loadString, it's actually an asynchronous method call. You can tell because it returns a Future<value> rather than just a value. This means that it doesn't immediately have a result of String, but will at some point in the future.

There are two main ways of dealing with asynchronicity in Dart; the first being to use async and await, the second being to use the futures directly. See the dart guide on Asynchronous Programming.

If you use future.then directly, you can do it from a normal function (i.e. from initState etc). You simply specify the callback and in the callback what to do with the result.

void printDailyNewsDigest() {
  final future = gatherNewsReports();
  future.then((news) => print(news));
}

If you want to use await as @Alexandre has illustrated, you need to mark the function you are using it from as async, i.e.:

Future<Void> printDailyNewsDigest() async {
  String news = await gatherNewsReports();
  print(news);
}

If you override a function (i.e. initState) you also need to make sure you don't change the return value. That should get caught by dart 2's typing most of the time, but void -> Future doesn't seem to be.

One last thing to note - if you're using the result of the data to build widgets, you'll probably want to look at using a FutureBuilder.

77
votes

Try out :

String data = await DefaultAssetBundle.of(context).loadString("assets/data.json");
final jsonResult = json.decode(data);
25
votes

I use the following to parse json in assets:

import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;
//...
Future<Map<String, dynamic>> parseJsonFromAssets(String assetsPath) async {
    print('--- Parse json from: $assetsPath');
    return rootBundle.loadString(assetsPath)
        .then((jsonStr) => jsonDecode(jsonStr));
  }

Usage async:

parseJsonFromAssets(path)
    .then((dmap) => {
    // here you get json `dmap` as Map<String, dynamic>
    print(dmap);
}));

Usage sync:

Map<String, dynamic> dmap = await parseJsonFromAssets('assets/test.json');
18
votes

You can use this code :)

loadJson() async {
  String data = await rootBundle.loadString('assets/json/keyboard.json');
  jsonResult = json.decode(data);
  print(jsonResult);
}

Can load on start :)

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) async {
      await loadJson();
    });
  }

Need to add the JSON on the asset

flutter:
  uses-material-design: true
  assets:
    - assets/json/keyboard.json