jsonflutterflutter-http

Why do I get 'data2' has not been initiliazed error here?


It makes no sense at this code. I am trying to grab some strings from the ALREADY INITIALIZED from the futurebuilder data, but can't do so. It gives me the data2 has not been initialized error. Here is data and data2, they are almost similiar, data works fine but data2 doesn't. Why is that?

late List<Album> data;
late List<String> data2;

Here is my code:

import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

const List<String> list = <String>['One', 'Two', 'Three', 'Four'];
Future<List<Album>> fetchAlbum() async {
  final response = await http.get(
      Uri.parse('https://my-json-server.typicode.com/fluttirci/testJson/db'));

  print(response);
  Map<String, dynamic> userMap = jsonDecode(response.body);
  if (response.statusCode == 200) {
    return (userMap['employees'] as List)
        .map((e) => Album.fromJson(e))
        .toList();
  } else {
    throw Exception('Failed to load album');
  }
}

class Album {
  final int userId;
  final int id;
  final String title;

  Album(this.userId, this.id, this.title);

  Album.fromJson(Map<String, dynamic> json)
      : userId = json['userId'],
        id = json['id'],
        title = json['title'];

  Map<String, dynamic> toJson() => {
        'userId': userId,
        'id': id,
        'title': title,
      };
}

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late Future<Album> futureAlbum;
  late Future<List<Album>> user;
  late List<Album> data;
  late List<String> data2;
  @override
  void initState() {
    super.initState();
    user = fetchAlbum();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fetch Data Example',
      theme: ThemeData(
        brightness: Brightness.dark,
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Fetch Data Example'),
        ),
        body: Column(children: <Widget>[
          Expanded(
            child: const DropdownButtonExample(),
          ),
          Expanded(
            child: FutureBuilder<List<Album>>(
              future: user,
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  data = snapshot.data ?? [];
                  print('${data[4].title}');

                  return ListView.builder(
                    itemBuilder: (context, index) {
                      data2[index] = data[index].title;
                      return Column(children: [
                        Text(data[index].title ?? ""),
                      ]);
                    },
                    itemCount: data.length,
                  );
                } else if (snapshot.hasError) {
                  return Text('${snapshot.error}');
                }
                return Center(
                  child: const CircularProgressIndicator(),
                );
              },
            ),
          )
        ]),
      ),
    );
  }
}

class DropdownButtonApp extends StatelessWidget {
  const DropdownButtonApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('DropdownButton Sample')),
        body: const Center(
          child: DropdownButtonExample(),
        ),
      ),
    );
  }
}

class DropdownButtonExample extends StatefulWidget {
  const DropdownButtonExample({super.key});

  @override
  State<DropdownButtonExample> createState() => _DropdownButtonExampleState();
}

class _DropdownButtonExampleState extends State<DropdownButtonExample> {
  String dropdownValue = list.first;

  @override
  Widget build(BuildContext context) {
    return DropdownButton<String>(
      value: dropdownValue,
      icon: const Icon(Icons.arrow_downward),
      elevation: 16,
      style: const TextStyle(color: Colors.deepPurple),
      underline: Container(
        height: 2,
        color: Colors.deepPurpleAccent,
      ),
      onChanged: (String? value) {
        // This is called when the user selects an item.
        setState(() {
          dropdownValue = value!;
        });
      },
      items: list.map<DropdownMenuItem<String>>((String value) {
        return DropdownMenuItem<String>(
          value: value,
          child: Text(value),
        );
      }).toList(),
    );
  }
}

Solution

  • For RangeError issue, your data2 is empty so you can search for index and pass your value to it, just add your string to it normally it will put that in right index, so change your listview's builder to this:

    return ListView.builder(
        itemBuilder: (context, index) {
          data2.add(data[index].title);//<--- change this
          return Column(children: [
            Text(data[index].title ?? ""),
          ]);
        },
        itemCount: data.length,
      );