App is not rebuilding screen after fetching data

  1. Summary of my problem
  • Details about my goal: hey there! I am working on a freelancer project and I need to fetch data from an API given a date selected by user. After fetch the data I need to build screens based on it.

  • Expected Results: what I need is to rebuild the entire screen to show the content of a given date selected by the user.

  • Actual Results: currently I can get the date selected by the user, fetch the data from the API and change the textual content on the screen. But I also have an audio player that uses an audio url from the API and it’s not being rebuilt. So I am always playing the audio from the previous date. I have also noticed that it’s not calling the loader when the user selects the date. But it changes the text on the screen after a while.

  • Error Messages (if any): there is no error messages.

  1. What have I tried so far: I have set a Provider to notify the date changes. When the date change I have a Consumer and inside of it I have a FutureBuilder which I expect to get the data. After I get the data I pass it to a stateless widget which I expect to be rebuilt.

  2. Here’s the minimum code you would need to reproduce the problem:

Here’s where I get the data:

  static const String id = 'liturgia_screen_state';
  const LiturgiaScreenState({Key? key}) : super(key: key);

  @override
  State<LiturgiaScreenState> createState() => _LiturgiaScreenStateState();
}

class _LiturgiaScreenStateState extends State<LiturgiaScreenState> {
  Future<Liturgia?> getLiturgia(Data data) async {
    Liturgia? liturgia = null;
    String? idSeq = await data.getIdSeq();
    try {
      var liturgiaFromDatabase =
          await LiturgiaDao().pegarLiturgiaDoBancoDeDados(idSeq.toString());
      liturgia = liturgiaFromDatabase;
    } on Exception {
      var liturgiaFromWebservice =
          await LiturgiaDao().pegarLiturgiaDoWebservice(idSeq.toString());
      liturgia = liturgiaFromWebservice;
    }
    return liturgia;
  }
  @override
  Widget build(BuildContext context) {
    return Consumer<Data>(
      builder: (context, data, child) {
        return FutureBuilder<Liturgia?>(
          future: getLiturgia(data),
          builder: (context, snapshot) {
            List<Widget> children;
            if (snapshot.hasData) {
              children = <Widget>[LiturgiaScreen(liturgia: snapshot.data!)];
            } else if (snapshot.hasError) {
              children = <Widget>[
                const Icon(
                  Icons.error_outline,
                  color: Colors.red,
                  size: 60,
                ),
                Padding(
                  padding: const EdgeInsets.only(top: 16),
                  child: Text('Error: ${snapshot.error}'),
                )
              ];
            } else {
              children = <Widget>[const LoadingState()];
            }
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: children,
            );
          },
        );
      },
    );
  }
} 

And here’s my stateless widget:

  final Liturgia liturgia;
  static const String id = 'liturgia_screen';
  const LiturgiaScreen({Key? key, required this.liturgia}) : super(key: key);

  List<Widget> getTabBar() {
    List<Widget> tabBar = [];
    List<String> titulos = [
      "1a LEITURA",
      "SALMO",
      liturgia.segundaLeituraCap.isNotEmpty ? "2a LEITURA" : "",
      "EVANGELHO"
    ];
    for (var titulo in titulos) {
      if (titulo.isNotEmpty) {
        tabBar.add(
          Tab(
            child: Text(
              titulo,
              overflow: TextOverflow.visible,
              style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: liturgia.segundaLeituraCap.isNotEmpty ? 10 : 13),
            ),
          ),
        );
      }
    }
    return tabBar;
  }

  //TODO cor litúrgica branca tem bullet com borda preta
  Widget _buildCabecalho(BuildContext context) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        DataWidget(mostrarAno: true),
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.end,
            children: [
              Text(
                liturgia.nome,
                textAlign: TextAlign.end,
                style: CustomTextStyle.kHeaderText(context),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.end,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Text(
                    "\u2022 ",
                    style: TextStyle(
                      fontSize: 30,
                      fontWeight: FontWeight.bold,
                      color: HexColor(liturgia.corLiturgicaHex),
                    ),
                  ),
                  Text(
                    "Cor Litúrgica: " + liturgia.corLiturgica,
                    overflow: TextOverflow.visible,
                    style: GoogleFonts.roboto(
                      textStyle: CustomTextStyle.kBulletText(context),
                    ),
                  ),
                ],
              )
            ],
          ),
        )
      ],
    );
  }

  List<Widget> getTabView(BuildContext context) {
    List<Widget> tabView = [];
    tabView.add(
      SingleChildScrollView(
        child: Column(
          children: [
            Column(
              children: [
                Container(
                  color: Theme.of(context).backgroundColor,
                  padding: const EdgeInsets.all(5),
                  child: _buildCabecalho(context),
                ),
                SafePlayer(
                    audioUrl: ApiPath.kLiturgiaAudioUrl.toString() +
                        liturgia.primeiraLeituraAudio),
                Text(
                  liturgia.primeiraLeituraCap,
                  style: CustomTextStyle.kReadingText(context),
                ),
                Html(data: liturgia.primeiraLeituraTxtHtml),
              ],
            ),
          ],
        ),
      ),
    );
    );
    return tabView;
  }

  @override
  Widget build(BuildContext context) => Expanded(
        child: LiturgiaTabView(
          tabBar: getTabBar(),
          tabBarView: getTabView(context),
        ),
      );
}

I think I am messing up with the state. So my question is: what would be the best way to get the date selected by the user and based on that get data from the API and build the entire screen from this data?

Thanks in advance.

Just solved changing the FutureBuilder to that:

FutureBuilder<Liturgia?>(
          future: getLiturgia(data),
          builder: (context, snapshot) {
            switch (snapshot.connectionState) {
              case ConnectionState.none:
                return Text('none');
              case ConnectionState.active:
              case ConnectionState.waiting:
                return const LoadingState();
              case ConnectionState.done:
                return LiturgiaScreen(liturgia: snapshot.data!);
              default:
                return Text('done');
            }
          },
        );