0

I am working on network requests within flutter using the flutter http package.

So far I have a welcome screen and a network helper.

The welcome screen has a scaffold with a list view and a bottom bar.

The list view will show text and an image per every list item.

The data for these items comes from an HTTP request.

That request is done in my network helper class.

In the welcome screen I have a function that I call from initState() that function will set a local variable to the json returned from the network helper but once I try to access the data from the variable it is null. However if I instead just print the data then the data is there.

My problem is I have accessed the data but cant think of the way I can pass that data into the list view.

Here is what my network helper class code looks like

import 'package:http/http.dart' as http;
import 'dart:convert';

class NetworkHelper{
  //Sets up search filter variables
  int year;
  String make;
  String model;
  String condition;
  String combustible;
  String style;
  String color;
  double minPrice;
  double maxPrice;

  Future fetchAlbum() async {
    http.Response response = await http.get('https://jsonplaceholder.typicode.com/todos');

    if (response.statusCode == 200) {
      String data = response.body;
      return jsonDecode(data);
    } else {
      throw Exception('Failed to load album');
    }
  }


}

And here is what my welcome screen looks like

import 'package:flutter/material.dart';
import 'package:components/appBarTitle.dart';
import 'package:components/bottomBarComponent.dart';
import 'package:convex_bottom_bar/convex_bottom_bar.dart';
import 'package:constants.dart';
import 'package:helpers/network_helper.dart';
import 'dart:convert';

class WelcomeScreen extends StatefulWidget {
  static String id = '/welcome_screen';
  @override
  _WelcomeScreenState createState() => _WelcomeScreenState();
}

class _WelcomeScreenState extends State<WelcomeScreen> {

  int _index = 0;

  NetworkHelper http = NetworkHelper();
  dynamic data;
  Future testMethod () async {
    this.data = await http.fetchAlbum();
    print(this.data);
  }

  @override
  void initState() {
    super.initState();
    testMethod();
  }

  @override
  Widget build(BuildContext context) {


    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        elevation: 0.0,
        title: AppBarTitle(),
      ),
      body: Padding(
        padding: const EdgeInsets.all(12.0),
        child: ListView(
          children: [
            ListBody(
              children: [
                Card(
                  child: Row(
                    children: [
                      Expanded(
                        child: Column(
                          children: [
                            Text('2017 Nissan', style: TextStyle(fontWeight: FontWeight.w300,)),
                            Text('Versa 1.6 SL', style: TextStyle(fontWeight: FontWeight.w100,)),
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Text('\$7,998.00', style: TextStyle(fontWeight: FontWeight.w200,)),
                            ),
                          ],
                        ),
                      ),
                      Expanded(
                        child: Image.network('https://via.placeholder.com/450/0000FF', scale: 4,),

                      ),

                    ],
                  ),
                ),
                Card(
                  child: Row(
                    children: [
                      Expanded(
                        child: Column(
                          children: [
                            Text('2017 Nissan', style: TextStyle(fontWeight: FontWeight.w300,)),
                            Text('Versa 1.6 SL', style: TextStyle(fontWeight: FontWeight.w100,)),
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Text('\$7,998.00', style: TextStyle(fontWeight: FontWeight.w200,)),
                            ),
                          ],
                        ),
                      ),
                      Expanded(
                        child: Image.network('https://via.placeholder.com/450/0000FF', scale: 4,),

                      ),

                    ],
                  ),
                ),
                Card(
                  child: Row(
                    children: [
                      Expanded(
                        child: Column(
                          children: [
                            Text('2017 Nissan', style: TextStyle(fontWeight: FontWeight.w300,)),
                            Text('Versa 1.6 SL', style: TextStyle(fontWeight: FontWeight.w100,)),
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Text('\$7,998.00', style: TextStyle(fontWeight: FontWeight.w200,)),
                            ),
                          ],
                        ),
                      ),
                      Expanded(
                        child: Image.network('https://via.placeholder.com/450/0000FF', scale: 4,),

                      ),

                    ],
                  ),
                ),
                Card(
                  child: Row(
                    children: [
                      Expanded(
                        child: Column(
                          children: [
                            Text('2017 Nissan', style: TextStyle(fontWeight: FontWeight.w300,)),
                            Text('Versa 1.6 SL', style: TextStyle(fontWeight: FontWeight.w100,)),
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Text('\$7,998.00', style: TextStyle(fontWeight: FontWeight.w200,)),
                            ),
                          ],
                        ),
                      ),
                      Expanded(
                        child: Image.network('https://via.placeholder.com/450/0000FF', scale: 4,),

                      ),

                    ],
                  ),
                ),
                Card(
                  child: Row(
                    children: [
                      Expanded(
                        child: Column(
                          children: [
                            Text('2017 Nissan', style: TextStyle(fontWeight: FontWeight.w300,)),
                            Text('Versa 1.6 SL', style: TextStyle(fontWeight: FontWeight.w100,)),
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Text('\$7,998.00', style: TextStyle(fontWeight: FontWeight.w200,)),
                            ),
                          ],
                        ),
                      ),
                      Expanded(
                        child: Image.network('https://via.placeholder.com/450/0000FF', scale: 4,),

                      ),

                    ],
                  ),
                ),
                Card(
                  child: Row(
                    children: [
                      Expanded(
                        child: Column(
                          children: [
                            Text('2017 Nissan', style: TextStyle(fontWeight: FontWeight.w300,)),
                            Text('Versa 1.6 SL', style: TextStyle(fontWeight: FontWeight.w100,)),
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Text('\$7,998.00', style: TextStyle(fontWeight: FontWeight.w200,)),
                            ),
                          ],
                        ),
                      ),
                      Expanded(
                        child: Image.network('https://via.placeholder.com/450/0000FF', scale: 4,),

                      ),

                    ],
                  ),
                )
              ],
            ),

          ],
        ),
      ),
        bottomNavigationBar: ConvexAppBar(
          backgroundColor: Color(0xffe74c3c),
          items: [
            TabItem(icon: Icons.home, title: 'Home'),
            TabItem(icon: Icons.map, title: 'Discover'),
            TabItem(icon: Icons.search, title: 'Busca'),
            TabItem(icon: Icons.person, title: 'Mi Cuenta'),
            TabItem(icon: Icons.build, title: 'Settings'),
          ],
          initialActiveIndex: 2,//optional, default as 0
          onTap: (int i) => print('click index=$i'),
        )
    );
  }
}
user2684521
  • 380
  • 4
  • 20

2 Answers2

1

Best practice would be to add some abstraction layers. Don't do this all in one place.

Create a data model for each piece of the incoming data. Then pass a list of those objects to the list view.

This example setups up the call and creates objects:

Future<List<HowTo>> fetchHowTos() async {
    // get the full web resource path based on environment, etc.
    String callPath = webAPI.getHowToPath();
    // just make the call, don't parse yet
    dynamic response = await makeCall(path: callPath);
    try {
      // this is the object type we want to convert the data into so it's easier to work with throughout your app
      List<HowTo> howTos = [];
      if (response != null) {
        // decode the data and then send each piece into a fromJson method
        dynamic howTosJson = json.decode(response.body);
        howTosJson.forEach((howToJson) {
          howTos.add(HowTo.fromJson(howToJson));
        });
      }
      return howTos;
    } catch (error, stacktrace) {
      logger.error(error, stacktrace, context: 'error parsing how to content');
      return [];
    }
  }

This code actually makes the call:

Future<dynamic> makeCall({String path}) async {
    try {
      final response = await network.getCall(path: path);

      if (response.statusCode == 200) {
        // If server returns an OK response, parse the JSON.
        return response;
      } else if (response.statusCode == 404) {
        // if no document exists return null.  expected for items without recommendations
        return null;
      } else {
        throw Exception('Failed http call. status: ' +
            response.statusCode.toString());
      }
    } catch (error, stacktrace) {
      logger.error(error, stacktrace, context: 'path: $path');
    }
}

This is the object to be created and used in your app

class HowTo {
  final String id;
  final String title;
  final int order;

  HowTo({
    this.id,
    this.title,
    this.order,
  });

  factory HowTo.from(HowTo howTo) {
    return HowTo(
      id: howTo.id,
      title: howTo.title,
      order: howTo.order,
    );
  }

  factory HowTo.fromJson(Map<String, dynamic> json) {
    
    return HowTo(
      id: json['id'] ?? '',
      title: json['Title'] ?? '',
      order: json['Order'] ?? 0,
    );
  }
}

pass the response from this to your list view wrapper

List<HowTo> howTos = await fetchHowTos();
1

You can copy paste run full code below
You can use FutureBuilder and ListView.builder
You can see working demo below
code snippet

Future<List<Payload>> _future;
NetworkHelper http = NetworkHelper();
Future<List<Payload>> testMethod() async {
    var data = await http.fetchAlbum();
    return data;
}

@override
void initState() {
    super.initState();
    _future = testMethod();
}
...  
FutureBuilder(
          future: _future,
          builder: (context, AsyncSnapshot<List<Payload>> snapshot) {
            ...
                } else {
                  return ListView.builder(
                      shrinkWrap: true,
                      itemCount: snapshot.data.length,
                      itemBuilder: (context, index) {
                        return Card(
                          elevation: 6.0,
                          child: Padding(
                            padding: const EdgeInsets.only(
                                top: 6.0,
                                bottom: 6.0,
                                left: 8.0,
                                right: 8.0),
                            child: ListTile(
                              title: Text(
                                  snapshot.data[index].id.toString()),
                              subtitle: Text(
                                snapshot.data[index].title,
                              ),

working demo

enter image description here

full code

import 'package:convex_bottom_bar/convex_bottom_bar.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
// To parse this JSON data, do
//
//     final payload = payloadFromJson(jsonString);

import 'dart:convert';

List<Payload> payloadFromJson(String str) =>
    List<Payload>.from(json.decode(str).map((x) => Payload.fromJson(x)));

String payloadToJson(List<Payload> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Payload {
  Payload({
    this.userId,
    this.id,
    this.title,
    this.completed,
  });

  int userId;
  int id;
  String title;
  bool completed;

  factory Payload.fromJson(Map<String, dynamic> json) => Payload(
        userId: json["userId"],
        id: json["id"],
        title: json["title"],
        completed: json["completed"],
      );

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

class NetworkHelper {
  //Sets up search filter variables
  int year;
  String make;
  String model;
  String condition;
  String combustible;
  String style;
  String color;
  double minPrice;
  double maxPrice;

  Future<List<Payload>> fetchAlbum() async {
    http.Response response =
        await http.get('https://jsonplaceholder.typicode.com/todos');

    if (response.statusCode == 200) {
      //String data = response.body;
      return payloadFromJson(response.body);
    } else {
      throw Exception('Failed to load album');
    }
  }
}

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: WelcomeScreen(),
    );
  }
}

class WelcomeScreen extends StatefulWidget {
  static String id = '/welcome_screen';
  @override
  _WelcomeScreenState createState() => _WelcomeScreenState();
}

class _WelcomeScreenState extends State<WelcomeScreen> {
  int _index = 0;
  Future<List<Payload>> _future;

  NetworkHelper http = NetworkHelper();

  Future<List<Payload>> testMethod() async {
    var data = await http.fetchAlbum();
    return data;
  }

  @override
  void initState() {
    super.initState();
    _future = testMethod();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.white,
        appBar: AppBar(
          elevation: 0.0,
          title: Text("title"),
        ),
        body: Column(
          children: [
            Expanded(
              flex: 1,
              child: FutureBuilder(
                  future: _future,
                  builder: (context, AsyncSnapshot<List<Payload>> snapshot) {
                    switch (snapshot.connectionState) {
                      case ConnectionState.none:
                        return Text('none');
                      case ConnectionState.waiting:
                        return Center(child: CircularProgressIndicator());
                      case ConnectionState.active:
                        return Text('');
                      case ConnectionState.done:
                        if (snapshot.hasError) {
                          return Text(
                            '${snapshot.error}',
                            style: TextStyle(color: Colors.red),
                          );
                        } else {
                          return ListView.builder(
                              shrinkWrap: true,
                              itemCount: snapshot.data.length,
                              itemBuilder: (context, index) {
                                return Card(
                                  elevation: 6.0,
                                  child: Padding(
                                    padding: const EdgeInsets.only(
                                        top: 6.0,
                                        bottom: 6.0,
                                        left: 8.0,
                                        right: 8.0),
                                    child: ListTile(
                                      title: Text(
                                          snapshot.data[index].id.toString()),
                                      subtitle: Text(
                                        snapshot.data[index].title,
                                      ),
                                    ),
                                  ),
                                );
                              });
                        }
                    }
                  }),
            ),
            Expanded(
              flex: 1,
              child: Padding(
                padding: const EdgeInsets.all(12.0),
                child: ListView(
                  shrinkWrap: true,
                  children: [
                    ListBody(
                      children: [
                        Card(
                          child: Row(
                            children: [
                              Expanded(
                                child: Column(
                                  children: [
                                    Text('2017 Nissan',
                                        style: TextStyle(
                                          fontWeight: FontWeight.w300,
                                        )),
                                    Text('Versa 1.6 SL',
                                        style: TextStyle(
                                          fontWeight: FontWeight.w100,
                                        )),
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text('\$7,998.00',
                                          style: TextStyle(
                                            fontWeight: FontWeight.w200,
                                          )),
                                    ),
                                  ],
                                ),
                              ),
                              Expanded(
                                child: Image.network(
                                  'https://via.placeholder.com/450/0000FF',
                                  scale: 4,
                                ),
                              ),
                            ],
                          ),
                        ),
                        Card(
                          child: Row(
                            children: [
                              Expanded(
                                child: Column(
                                  children: [
                                    Text('2017 Nissan',
                                        style: TextStyle(
                                          fontWeight: FontWeight.w300,
                                        )),
                                    Text('Versa 1.6 SL',
                                        style: TextStyle(
                                          fontWeight: FontWeight.w100,
                                        )),
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text('\$7,998.00',
                                          style: TextStyle(
                                            fontWeight: FontWeight.w200,
                                          )),
                                    ),
                                  ],
                                ),
                              ),
                              Expanded(
                                child: Image.network(
                                  'https://via.placeholder.com/450/0000FF',
                                  scale: 4,
                                ),
                              ),
                            ],
                          ),
                        ),
                        Card(
                          child: Row(
                            children: [
                              Expanded(
                                child: Column(
                                  children: [
                                    Text('2017 Nissan',
                                        style: TextStyle(
                                          fontWeight: FontWeight.w300,
                                        )),
                                    Text('Versa 1.6 SL',
                                        style: TextStyle(
                                          fontWeight: FontWeight.w100,
                                        )),
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text('\$7,998.00',
                                          style: TextStyle(
                                            fontWeight: FontWeight.w200,
                                          )),
                                    ),
                                  ],
                                ),
                              ),
                              Expanded(
                                child: Image.network(
                                  'https://via.placeholder.com/450/0000FF',
                                  scale: 4,
                                ),
                              ),
                            ],
                          ),
                        ),
                        Card(
                          child: Row(
                            children: [
                              Expanded(
                                child: Column(
                                  children: [
                                    Text('2017 Nissan',
                                        style: TextStyle(
                                          fontWeight: FontWeight.w300,
                                        )),
                                    Text('Versa 1.6 SL',
                                        style: TextStyle(
                                          fontWeight: FontWeight.w100,
                                        )),
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text('\$7,998.00',
                                          style: TextStyle(
                                            fontWeight: FontWeight.w200,
                                          )),
                                    ),
                                  ],
                                ),
                              ),
                              Expanded(
                                child: Image.network(
                                  'https://via.placeholder.com/450/0000FF',
                                  scale: 4,
                                ),
                              ),
                            ],
                          ),
                        ),
                        Card(
                          child: Row(
                            children: [
                              Expanded(
                                child: Column(
                                  children: [
                                    Text('2017 Nissan',
                                        style: TextStyle(
                                          fontWeight: FontWeight.w300,
                                        )),
                                    Text('Versa 1.6 SL',
                                        style: TextStyle(
                                          fontWeight: FontWeight.w100,
                                        )),
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text('\$7,998.00',
                                          style: TextStyle(
                                            fontWeight: FontWeight.w200,
                                          )),
                                    ),
                                  ],
                                ),
                              ),
                              Expanded(
                                child: Image.network(
                                  'https://via.placeholder.com/450/0000FF',
                                  scale: 4,
                                ),
                              ),
                            ],
                          ),
                        ),
                        Card(
                          child: Row(
                            children: [
                              Expanded(
                                child: Column(
                                  children: [
                                    Text('2017 Nissan',
                                        style: TextStyle(
                                          fontWeight: FontWeight.w300,
                                        )),
                                    Text('Versa 1.6 SL',
                                        style: TextStyle(
                                          fontWeight: FontWeight.w100,
                                        )),
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text('\$7,998.00',
                                          style: TextStyle(
                                            fontWeight: FontWeight.w200,
                                          )),
                                    ),
                                  ],
                                ),
                              ),
                              Expanded(
                                child: Image.network(
                                  'https://via.placeholder.com/450/0000FF',
                                  scale: 4,
                                ),
                              ),
                            ],
                          ),
                        )
                      ],
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
        bottomNavigationBar: ConvexAppBar(
          backgroundColor: Color(0xffe74c3c),
          items: [
            TabItem(icon: Icons.home, title: 'Home'),
            TabItem(icon: Icons.map, title: 'Discover'),
            TabItem(icon: Icons.search, title: 'Busca'),
            TabItem(icon: Icons.person, title: 'Mi Cuenta'),
            TabItem(icon: Icons.build, title: 'Settings'),
          ],
          initialActiveIndex: 2, //optional, default as 0
          onTap: (int i) => print('click index=$i'),
        ));
  }
}
chunhunghan
  • 51,087
  • 5
  • 102
  • 120