Home > Blockchain >  Flutter Riverpod: FutureProvider family never gets resolved
Flutter Riverpod: FutureProvider family never gets resolved

Time:05-29

I am new to Flutter Riverpod package. I implemented a FutureProvider family to handle async SDK calls depending on a datetime argument (the period), following the official Riverpod documentation quite closely.

Event provider (/providers/events.dart)

import 'dart:convert';
import 'dart:developer';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../models/event.dart';

const _platform = MethodChannel('com.eventSdk/sdk');

final eventsFamily =
    FutureProvider.family<List<Event>, Map<String, int>>(
        (ref, period) async {
  List<Event> events = [];
  String response = await _platform.invokeMethod(
      'fetchEventHistory', {'from': period['from'], 'to': period['to']});
  List rawEvents = jsonDecode(response);
  for (var i = 0; i < rawEvents.length; i  ) {
    events.add(Activity.fromJson(rawEvents[i]));
  }
  log(events.toString()); // <- This successfully logs the events, meaning the  SDK call is successfully awaited and answers
  return events;
});

Widget (/screens/stats.dart)

import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../../providers/events.dart';
import '../../models/event.dart';

class StatsPage extends ConsumerWidget {
  const StatsPage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final Map<String, int> period = {
      "from": 1609477684000, // epoch in milliseconds (int)
      "to": DateTime.now().toUtc().millisecondsSinceEpoch // epoch in milliseconds (int)
    };
    AsyncValue<List<Event>> events = ref.watch(eventsFamily(period));
    return events.when(
        loading: () => const CircularProgressIndicator(),
        error: (err, stack) => Text('Error: $err'),
        data: (events) {
          log(events.toString());
          return const Text("Loading successful!");
        });
  }
}

The log in the provider is successfully logging back the expected SDK output, so I assume the FutureProvider family is OK.

But the log in the consumer widget who reads the provider is never called, and the widget always stays in loading state, so it seems the promise from the provider is never resolved. What am I doing wrong here?

I tried from a ConsumerWidget, as well as from a ConsumerStatefulWidget /ConsumerState. Also tried with events.value.toString(), but it seems it's never resolved neither.

CodePudding user response:

The problem is most likely because period is in the build method.

Try this:

class StatsPage extends ConsumerWidget {
  const StatsPage({Key? key, required this.title}) : super(key: key);
  final String title;

  final Map<String, int> period = {
      "from": 1609477684000, // epoch in milliseconds (int)
      "to": DateTime.now().toUtc().millisecondsSinceEpoch // epoch in milliseconds (int)
    };

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    AsyncValue<List<Event>> events = ref.watch(eventsFamily(period));
    return events.when(
        loading: () => const CircularProgressIndicator(),
        error: (err, stack) => Text('Error: $err'),
        data: (events) {
          log(events.toString());
          return const Text("Loading successful!");
        });
  }
}
  • Related