Flutter read data from local JSON files | ListView

We will learn and deepen our understanding about reading data from local JSON files for Flutter projects. We will also see how to render the json decoded data into a ListView.

First make sure that you create a new project and in the project root folder create a new folder name assets and create a new file name sample.json

You also need to make sure that you have correct file path in pubspec.yaml file.

Now let's take a look at sample.json file. Our json file has three jsons or three Maps inside a list. And each Map has three properties. The properties are

  1. id
  2. name
  3. description
{
  "items": [
    {
      "id": "p1",
      "name": "Item 1",
      "description": "Description 1"
    },
    {
      "id": "p2",
      "name": "Item 2",
      "description": "Description 2"
    },
    {
      "id": "p3",
      "name": "Item 3",
      "description": "Description 3"
    }
  ]
}

We load the JSON file using a function named readJson(). 

  Future<void> readJson() async {
    final String response = await rootBundle.loadString('assets/sample.json');
    final data = await json.decode(response);
    setState(() {
      _items = data["items"];
      print("..number of items ${_items.length}");
    });
  }

rootBundle.loadString() is the core function that loads the json files from app itself. This function takes the path of the stored assets. If your path is wrong, you will get error, like unable to load. Of course after this, we would need to decode it. We decoded it using json.decode() function.

After decoding we used setState() to trigger UI build. In the build() method we will access _items variable, _items holds our json as string.

You also need to check how we assigned data['items'] to _items. 

After that, we show or render the decoded data in ListView.builder.  ListView.builder is a great widget to render data from a List.

 ListView.builder(
              itemCount: _items.length,
              itemBuilder: (context, index) {
                return Card(
                  key: ValueKey(_items[index]["id"]),
                  margin: const EdgeInsets.all(10),
                  color: Colors.amber.shade100,
                  child: ListTile(
                    leading: Text(_items[index]["id"]),
                    title: Text(_items[index]["name"]),
                    subtitle: Text(_items[index]["description"]),
                  ),
                );
              },
            ),

See how ListView.builder renders data using a ListTile.

The complete code

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // Hide the debug banner
      debugShowCheckedModeBanner: false,
      title: 'dbestech',
      theme: ThemeData(
        useMaterial3: true,
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  List _items = [];

  // Fetch content from the json file
  Future<void> readJson() async {
    final String response = await rootBundle.loadString('assets/sample.json');
    final data = await json.decode(response);
    setState(() {
      _items = data["items"];
      print("..number of items ${_items.length}");
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: const Text(
          'dbestech',
        ),
      ),
      body:Column(
        children: [
          _items.isNotEmpty?Expanded(
            child: ListView.builder(
              itemCount: _items.length,
              itemBuilder: (context, index) {
                return Card(
                  key: ValueKey(_items[index]["id"]),
                  margin: const EdgeInsets.all(10),
                  color: Colors.amber.shade100,
                  child: ListTile(
                    leading: Text(_items[index]["id"]),
                    title: Text(_items[index]["name"]),
                    subtitle: Text(_items[index]["description"]),
                  ),
                );
              },
            ),
          ): ElevatedButton(
              onPressed: () {
                readJson();
              },
              child: Center(child: Text("Load Json")))
        ],
      ),
    );
  }
}

Make sure at the top you import the below files

import 'dart:async';
import 'dart:convert';

Recent posts