Ошибка: не удалось найти правильного поставщика над этим виджетом

Хорошо, я застрял в этой проблеме, используя FutureProvider.

Я уже создал FutureProvider над своим MaterialApp, так что его следует распознать, верно?

Мое дерево виджетов выглядит примерно так:

MyApp >> Home >> CardVehicle

Вот мой код main.dart, в котором я создаю объект Provider:

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

class MyApp extends StatelessWidget {
  final Service service = Service();

  @override
  Widget build(BuildContext context) {
    return FutureProvider(
      create: (_) => service.fetchCarYear(),
      catchError: (_, error) => print(error),
      child: MaterialApp(
        title: 'KPM Demo',
        theme: ThemeData(
          primarySwatch: Colors.amber,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: Home(),
      ),
    );
  }
}

мой фиктивный класс обслуживания:

class Service {
  Future<CarYear> fetchCarYear() async {
    CarYear carYear = CarYear();

    final response = await Future.delayed(
      Duration(milliseconds: 500),
      () => jsonEncode({
        "data": [
          {"year": "2020"},
          {"year": "2019"},
          {"year": "2018"}
        ]
      }),
    );

    carYear = CarYear.fromJson(jsonDecode(response));

    return carYear;
  }
}

Вот куда я поставил своего Провайдера:

class CardVehicle extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    CarYear carYear = Provider.of<CarYear>(context);

    return Container(
      padding: EdgeInsets.all(20),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(10),
        color: Colors.white,
      ),
      child: Column(
        children: <Widget>[
          DropdownButton(
            isExpanded: true,
            icon: Icon(Icons.keyboard_arrow_down),
            items: carYear.data
                .map((item) => DropdownMenuItem(child: Text(item.year)))
                .toList() ?? null,
            onChanged: null,
          ),
        ],
      ),
    );
  }
}

Я где-то ошибся? Пожалуйста помоги!

Изменить: вот мой класс CarYear:

class CarYear {
  List<Data> data;

  CarYear({this.data});

  CarYear.fromJson(Map<String, dynamic> json) {
    if (json['data'] != null) {
      data = new List<Data>();
      json['data'].forEach((v) {
        data.add(new Data.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    if (this.data != null) {
      data['data'] = this.data.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class Data {
  String year;

  Data({this.year});

  Data.fromJson(Map<String, dynamic> json) {
    year = json['year'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['year'] = this.year;
    return data;
  }
}

person Serpentarius    schedule 13.04.2020    source источник
comment
Пожалуйста, введите код для класса CarYear ()   -  person FloW    schedule 13.04.2020
comment
Я добавил свой класс CarYear. Он был сгенерирован с json на сайт dart.   -  person Serpentarius    schedule 13.04.2020


Ответы (3)


Исходя из другого вопроса, который вы разместили.

Вам необходимо изменить catchError вашего futureProvider, чтобы вернуть Год автомобиля вместо недействительного. Теперь futureProvider относится к типу Dynamic, а provider.of ищет не поставщика dynamic, а поставщика CarYear.

Чтобы этого избежать, заставьте catchError возвращать пустой CarYear или создайте исключение.

Надеюсь, это поможет!

person Francisco Javier Snchez    schedule 13.04.2020

лучше сделать это с помощью ChangeNotifierProvider

в основном вы создали с помощью MultiProvider

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => Service()),
      ],
      child: MaterialApp(..)
    )
  }

в классе обслуживания я добавил extends ChangeNotifiere, когда notifyListeners() звонит, все потребители обновляются

class Service extends ChangeNotifier {

  // Variable set in Service
  CarYear _carYear = new CarYear();
  CarYear get carYear => _carYear;

  // init MultiProvider create() =>
  Service() {
    fetchCarYear();
  }

  Future<CarYear> fetchCarYear() async {
    _carYear = CarYear();

    final response = await Future.delayed(
      Duration(milliseconds: 500),
          () => jsonEncode({
        "data": [
          {"year": "2020"},
          {"year": "2019"},
          {"year": "2018"}
        ]
      }),
    );

    // update _carYear Variable
    _carYear = CarYear.fromJson(jsonDecode(response));

    // all Consumer get a refresh()
    notifyListeners();
  }

}

в CardVehicle я разместил Consumer, но CarYear carYear = Provider.of<Service>(context).carYear тоже работает .. но с Provider.of вы обновляете каждые notifyListeners() весь виджет

class CardVehicle extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    return Container(
      padding: EdgeInsets.all(20),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(10),
        color: Colors.white,
      ),
      child: Column(
        children: <Widget>[

          // its better you do it here with a Consumer, because not the whole widget is updating
          new Consumer<Service>(
              builder: (context, service, child) => new DropdownButton(
                  isExpanded: true,
                  icon: Icon(Icons.keyboard_arrow_down),
                  items: service.carYear.data
                      .map((item) => DropdownMenuItem(child: Text(item.year), value: item.year,))
                      .toList(),
                  onChanged: (value) {
                    print(value);
                  },
                ),
            ),
        ],
      ),
    );
  }

}
person FloW    schedule 13.04.2020
comment
ChangeNotifier похож на первого провайдера, которого я узнал. Я тоже хочу использовать другого провайдера. Спасибо за ответ. - person Serpentarius; 14.04.2020

Пример только с FutureProvider

MultiProvider(
  providers: [
    FutureProvider(create: (_) => Service().fetchCarYear()),
  ],
  child: MaterialApp(..)

Класс обслуживания с возвратом CarYear

class Service {

  // Variable set in Service
  CarYear _carYear;

  Future<CarYear> fetchCarYear() async {
    _carYear = CarYear(data: new List());

    final response = await Future.delayed(
      Duration(milliseconds: 500),
          () => jsonEncode({
        "data": [
          {"year": "2020"},
          {"year": "2019"},
          {"year": "2018"}
        ]
      }),
    );

    // update _carYear Variable
    _carYear = CarYear.fromJson(jsonDecode(response));

    // all Consumer get a refresh()
    //notifyListeners();
    return _carYear;
  }

}

и CardVehicle с CarYear carYear = Provider.of<CarYear>(context);

class CardVehicle extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    CarYear carYear = Provider.of<CarYear>(context);

    return Container(
      padding: EdgeInsets.all(20),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(10),
        color: Colors.white,
      ),
      child: Column(
        children: <Widget>[
          new DropdownButton(
            isExpanded: true,
            icon: Icon(Icons.keyboard_arrow_down),
            items: carYear != null ? carYear.data
                .map((item) => DropdownMenuItem(child: Text(item.year), value: item.year,))
                .toList() : null,
            onChanged: (value) {
              print(value);
            },
          ),
        ],
      ),
    );
  }

}
person FloW    schedule 14.04.2020
comment
только catchError в вашем FutureProvider делает ошибку - person FloW; 14.04.2020