Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

FutureBuilder<List<Contact>>: Build functions must never return null

Aparentemente, a função "findAll" está devolvendo nulo e não estou entendendo o motivo.

Código da lista de Contatos:

class ContactsList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Contatos'),
      ),
      body: FutureBuilder<List<Contact>>(
        initialData: List(),
        future: Future.delayed(Duration(seconds: 0)).then((value) {
          findAll();
        }),
        builder: (context, snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.none:
              break;
            case ConnectionState.waiting:
              Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    CircularProgressIndicator(),
                    Text('Carregando...')
                  ],
                ),
              );
              break;
            case ConnectionState.active:
              break;
            case ConnectionState.done:
              if (snapshot.data != null) {
                final List<Contact> contacts = snapshot.data;
                ListView.builder(
                  itemBuilder: (context, index) {
                    final Contact contact = contacts[index];
                    return _ContactItem(contact);
                  },
                  itemCount: contacts.length,
                );
              } else {
                return Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      Text('snapshot.data é nulo'),
                    ],
                  ),
                );
              }
              break;
            default:
              return Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    Text('Unknown error'),
                  ],
                ),
              );
          }
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.of(context)
              .push(
                MaterialPageRoute(
                  builder: (context) => ContactForm(),
                ),
              )
              .then(
                (newContact) => debugPrint(newContact.toString()),
              );
        },
        child: Icon(
          Icons.add,
        ),
      ),
    );
  }
}

class _ContactItem extends StatelessWidget {
  final Contact contact;
  _ContactItem(this.contact);

  @override
  Widget build(BuildContext context) {
    return Card(
      child: ListTile(
        title: Text(
          contact.name,
          style: TextStyle(
            fontSize: 24.0,
          ),
        ),
        subtitle: Text(
          contact.accountNumber.toString(),
          style: TextStyle(
            fontSize: 16.0,
          ),
        ),
      ),
    );
  }
}

Código da função findAll:

Future<List<Contact>> findAll() {
  return createDatabase().then((db) {
    return db.query('contacts').then((maps) {
      final List<Contact> contacts = List();
      for (Map<String, dynamic> map in maps) {
        final Contact contact = Contact(
          map['id'],
          map['name'],
          map['account_number'],
        );
        contacts.add(contact);
      }
      return contacts;
    });
  });
}

Link do Git: https://github.com/biiaFlor/bytebank_flutter/tree/feature/ManipulacaoContatos

4 respostas

Olá Beatriz, tudo bem com você?

Acontece que em alguns pontos do seu código no contact_list.dart você esqueceu de utilizar o return, por exemplo:

future: Future.delayed(Duration(seconds: 0)).then((value) {
          findAll();
}),

Aqui, como você optou por não utilizar arrow functions, precisamos explicitamente declarar o retorno:

future: Future.delayed(Duration(seconds: 0)).then((value) {
          return findAll();
}),

future: Future.delayed(Duration(seconds: 0)).then((value) => findAll()),

Da segunda forma, não precisamos, pois Arrow Functions tem retorno implícito :)

Um outro ponto do seu código, é que nos cases do Switch, você esqueceu de colocar o return também, o builder espera que seja retornado um Widget, então precisamos colocar em todos:

        builder: (context, snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.none:
              break;
            case ConnectionState.waiting:
              return Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    CircularProgressIndicator(),
                    Text('Carregando...')
                  ],
                ),
              );
              break;
            case ConnectionState.active:
              break;
            case ConnectionState.done:
              if (snapshot.data != null) {
                final List<Contact> contacts = snapshot.data;
                return ListView.builder(
                  itemBuilder: (context, index) {
                    final Contact contact = contacts[index];
                    return _ContactItem(contact);
                  },
                  itemCount: contacts.length,
                );
              } else {
                return Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      Text('snapshot.data é nulo'),
                    ],
                  ),
                );
              }
              break;
            default:
              return Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    Text('Unknown error'),
                  ],
                ),
              );
          }
        },
      ),

Dessa maneira seu código funcionara corretamente :)

Abraços e Bons Estudos :)

Olá Geovani, estou bem e você?

Agradeço a ajuda! Segui suas instruções mas o código continua a não funcionar, dessa vez da esse erro: lib/screens/contacts_list.dart:15:70: Error: A value of type 'Future<List<Contact/1*/>>' can't be assigned to a variable of type 'FutureOr<List<Contact/2*/>>'.

Você sabe me dizer o que posso fazer?

solução!

Olá Beatriz =D

Então, eu peguei seu projeto novamente no github e a única coisa que acredito que pode ter dado problema foi os seus imports, eu rodei o seu projeto corrigindo isso e não tive problema nenhum,

As mudanças necessárias foram:

  1. No main eu tirei o código do debug:
import 'package:flutter/material.dart';

import 'Screens/Dashboard.dart';

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

class BytebankApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      home: Dashboard(),
    );
  }
}
  1. contact_list.dart

Estava

import 'package:bytebank/DataBase/app_database.dart';
import 'package:bytebank/Models/contact.dart';
import 'package:bytebank/screens/contact_form.dart';
import 'package:flutter/material.dart';

Dessa maneira o compilador reclamava da pasta screens que está com letra maiúscula

import 'package:bytebank/Models/contact.dart';
import 'package:flutter/material.dart';
import '../DataBase/app_database.dart';

import 'contact_form.dart';

O ideal é deixar todos imports igual esta o contact_form da maneira relativa, iremos utilizar o absoluto (package:..../) apenas para bibliotecas que não são do nosso projeto ( como o sqflite, material, path)

  1. app_database.dart

Estava:

import 'package:bytebank/models/contact.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

Para:

import '../Models/contact.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

Novamente a pasta com letra maiúscula

  1. dashboard.dart
import 'package:bytebank/screens/contacts_list.dart';
import 'package:flutter/material.dart';

Para:

import 'package:flutter/material.dart';
import 'contacts_list.dart';
  1. contact.dart
import 'package:bytebank/models/contact.dart';
import 'package:flutter/material.dart';

Para:

import 'package:flutter/material.dart';
import '../Models/contact.dart';

Após consertar todos erros de importo projeto rodou normalmente e todo processo foi um sucesso

Veja o fluxo do seu projeto:

image

Ao clicar no botão da dashboard, temos o Loading do Center e depois fica estável com a lista vazia

image

Ao clicar no FloatingActionButton foi corretamente para tela de forumlário

Após a inserção no terminal:

I/flutter (32409): Contact{id: 0, name: Geovani    , accountNumber: 321321312}

E voltou para a lista de maneira natural, sem nenhum erro ou exceção

Pode tentar essas correções? As vezes é bom desinstalar o aplicativo, arrumar os imports e dar um flutter run para reinstalar, seja no seu celular, quanto no emulador para ver se volta ao normal :)

Abraços e Bons Estudos!

Olá, Geovani! =D

Segui suas recomendações e está funcionando normalmente agora, muito obrigada pela ajuda!

Abraços!