在此ServerList小部件上方找不到正确的Provider <ServerResponse>

时间:2020-06-26 17:36:24

标签: flutter provider state-management flutter-state

我不明白为什么我的FutureProvider不能正常运行,而ChangeNotifierProvider却可以正常运行。

无论我做什么,即使我删除ChangeNotifierProvider并将其替换为FutureProvider或将我的MaterialApp小部件包装为FutureProvider或用户MultiProvider也会给我同样的错误。

import 'package:provider/provider.dart';
import 'package:sprightly/new/Constants.dart';
import 'package:sprightly/new/ConstraintProvider.dart';
import 'package:sprightly/new/SearchBox.dart';
import 'package:sprightly/new/api/ApiService.dart';
import 'package:sprightly/new/model/ServerResponse.dart';
import 'package:sprightly/new/profile/Profile.dart';

class Home extends StatelessWidget {
  const Home({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: green,
        elevation: 0,
      ),
      body: Background(),
    );
  }
}

class Background extends StatelessWidget {
  double width(double width) {
    return width > 500 ? width * 0.6 : width;
  }

  void setConstraints(BuildContext context, BoxConstraints constraints) {
    Provider.of<Constraint>(context, listen: false)
        .setHeight(constraints.maxHeight);
    Provider.of<Constraint>(context, listen: false)
        .setWidth(constraints.maxWidth);
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => Constraint(),
      child: LayoutBuilder(builder: (context, constraint) {
        setConstraints(context, constraint);
        return Stack(
          children: [
            Column(
              children: [
                Container(
                  width: double.infinity,
                  height: MediaQuery.of(context).size.height * 0.20,
                  color: green,
                  child: Align(
                    alignment: Alignment.centerRight,
                    child: Image.asset(
                      'assets/images/backdrop.svg',
                    ),
                  ),
                ),
              ],
            ),
            Center(
              child: Padding(
                padding: EdgeInsets.only(
                  top: MediaQuery.of(context).size.height * .10,
                ),
                child: ClipRRect(
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(30),
                    topRight: Radius.circular(30),
                  ),
                  child: Container(
                    width: width(constraint.maxWidth),
                    color: Color(0xffF0F0F0),
                    child: Foreground(),
                  ),
                ),
              ),
            ),
          ],
        );
      }),
    );
  }
}

class Foreground extends StatelessWidget {
  final ApiService api = ApiService();

  @override
  Widget build(BuildContext context) {
    return FutureProvider(
      create: (context) => api.getServer(),
      catchError: (context, error) => print(error.toString()),
      child: Column(
        children: [
          Padding(
            padding: const EdgeInsets.only(
              top: 20,
              left: 20,
              right: 20,
            ),
            child: SearchBox(),
          ),
          SizedBox(
            height: 10,
          ),
          ServerList(),
        ],
      ),
    );
  }
}

class ServerList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    ServerResponse response = Provider.of<ServerResponse>(context);

    return Expanded(
      child: ListView.builder(
          itemCount: response.response.length,
          itemBuilder: (context, index) {
            var width = Provider.of<Constraint>(context).getWidth();
            print(width);
            return Profile(index);
          }),
    );
  }
}

这是错误


Error: Could not find the correct Provider<ServerResponse> above this ServerList Widget

This likely happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:

- The provider you are trying to read is in a different route.

  Providers are "scoped". So if you insert of provider inside a route, then
  other routes will not be able to access that provider.

- You used a `BuildContext` that is an ancestor of the provider you are trying to read.

  Make sure that ServerList is under your MultiProvider/Provider<ServerResponse>.
  This usually happen when you are creating a provider and trying to read it immediatly.

  For example, instead of:

  
  Widget build(BuildContext context) {
    return Provider<Example>(
      create: (_) => Example(),
      // Will throw a ProviderNotFoundError, because `context` is associated
      // to the widget that is the parent of `Provider<Example>`
      child: Text(context.watch<Example>()),
    ),
  }
  

  consider using `builder` like so:

  
  Widget build(BuildContext context) {
    return Provider<Example>(
      create: (_) => Example(),
      // we use `builder` to obtain a new `BuildContext` that has access to the provider
      builer: (context) {
        // No longer throws
        return Text(context.watch<Example>()),
      }
    ),
  }

1 个答案:

答案 0 :(得分:0)

我发现了这个问题,在声明FutureProvider时提供类型是一个愚蠢的问题。

只需更改此内容即可

// --- client ---

FileDescriptorProto local_proto = request->custom_proto(); //this is from the server

//const google::protobuf::Descriptor* message_desc = local_proto.GetDescriptor();

DescriptorPool pool_;
const FileDescriptor* local_proto_;
local_proto_ = pool_.BuildFile(local_proto);

// display message contents
const google::protobuf::Descriptor* message_desc = local_proto_->FindMessageTypeByName("AttribRow");
cout << "Field Count: " << message_desc->field_count() << endl;

google::protobuf::DynamicMessageFactory factory;
const google::protobuf::Message* mutable_msg = factory.GetPrototype(message_desc);

const Reflection* reflection = mutable_msg->GetReflection();
const Descriptor* descriptor = mutable_msg->GetDescriptor();

for (int i = 0; i < descriptor->field_count(); i++) {
    const FieldDescriptor* fd = descriptor->field(i);
    cout << fd->name() << " -> " << reflection->GetInt64(*mutable_msg, fd) << endl; //this fails
}

对此:

class Foreground extends StatelessWidget {
  final ApiService api = ApiService();

  @override
  Widget build(BuildContext context) {
    return FutureProvider(
      create: (context) => api.getServer(),
      catchError: (context, error) => print(error.toString()),
      child: Column(
        children: [
          Padding(
            padding: const EdgeInsets.only(
              top: 20,
              left: 20,
              right: 20,
            ),
            child: SearchBox(),
          ),
          SizedBox(
            height: 10,
          ),
          ServerList(),
        ],
      ),
    );
  }
}