【问题标题】:Flutter: Type <> is not a subtype of <>... but it isFlutter:类型 <> 不是 <> 的子类型...但它是
【发布时间】:2019-12-27 04:22:02
【问题描述】:

免责声明:我知道有几个有点相似的问题,但没有一个能帮助我理解这个特定案例中的问题。


我创建了一个实用小部件,它接受ChangeNotifier,并在数据更改时自动重建小部件。

这个小部件的代码略有缩短,但问题是可见的:

class ChangeNotifierConsumer<T extends ChangeNotifier> extends StatefulWidget {
  const ChangeNotifierConsumer({
    Key key,
    @required this.notifier,
    @required this.builder,
  }) : super(key: key);

  final T notifier;

  final Widget Function(BuildContext context, T cache) builder;

  @override
  _ChangeNotifierConsumerState createState() => _ChangeNotifierConsumerState();
}

class _ChangeNotifierConsumerState extends State<ChangeNotifierConsumer> {
  @override
  Widget build(BuildContext context) => widget.builder(context, widget.notifier);
}
class Model extends ChangeNotifier { ... }

然后我会按如下方式使用小部件,但这就是发生错误的地方:

ChangeNotifierConsumer<Model>(
    notifier: Model(),
    builder: (BuildContext context, Model model) { ... }
)

确切的错误信息是:

type '(BuildContext, Model) =&gt; ListView' is not a subtype of type '(BuildContext, ChangeNotifier) =&gt; Widget'

dart 分析也没有编译时错误或输出,只是在运行时失败。

尽管模型扩展了 ChangeNotifier,为什么会出现此错误?

如果我按如下方式使用Builder,那就没有问题了:

    builder: (BuildContext context, dynamic model) { 
       Model model = model as Model;    
    }

【问题讨论】:

  • 好吧,首先,您的实用程序是内置的:AnimatedBuilder
  • 我知道AnimatedBuilder,但正如我所写的“小部件有点短”。我在里面做了额外的事情,AnimatedBuilder 没有。除此之外,我在其他小部件上也遇到了类似的错误,但这个是最容易描述问题的。
  • 在使用的时候能把你正在使用的代码贴在builder函数里吗?
  • 你能发布一个最小的、完整的、可验证的例子吗?我无法重现您的问题。错误消息是正确的,因为(BuildContext, Model) =&gt; ListView 不是(BuildContext, ChangeNotifier) =&gt; Widget 的子类型不是,但不清楚为什么它需要ChangeNotifier 参数。您确定您提供了遇到错误的确切代码吗?
  • 我怀疑您有名称冲突,您使用的这个Model 不是您定义的模型类。只需在 ChangeNotifierConsumer&lt;Model&gt;( 中的 Model 上按 ctrl+click(Intellij) 并查看它会将您带到哪里。

标签: inheritance flutter dart casting


【解决方案1】:

恕我直言,您扩展 ChangeNotifier 的方法有一个小错误。

在 OOP 中扩展某些东西是指“是一个”。 例如,Lion extends Animal => Lion 是 Animal。

在你的情况下,通过扩展 ChangeNotifier,你基本上说:

Model 是一个 ChangeNotifier ,但事实并非如此。如果我错了,请纠正我。

我厌倦了思考类型问题,但不知道为什么会这样。 同时,我编写了一个示例,该示例将是 T 类型保存并按预期工作。

完整的工作示例:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  TestModel _model = TestModel(
    'id', 'name'
  );

  _changeValue(){
    _model.setId('newId');
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Column(
          children: <Widget>[
            Container(
                padding: EdgeInsets.all(56.0),
                child: ChangeNotifierConsumer<TestModel>(
                  model: _model,
                  builder: (BuildContext context) {
                    return Column(
                      children: <Widget>[
                        Text(_model.id),
                        RaisedButton(
                          child: Text(_model.name),
                          onPressed: _changeValue,
                        )
                      ],
                    );
                  },
                )), Text(_model.id)
          ],
        )
      )
    );
  }
}


class ChangeNotifierConsumer<T extends Model> extends StatefulWidget {
  ChangeNotifierConsumer({
    Key key,
    @required this.model,
    @required this.builder,
  }) : super(key: key);

  final T model;
  final Widget Function(BuildContext context) builder;
  @override
  _ChangeNotifierConsumerState createState() => _ChangeNotifierConsumerState();
}

class _ChangeNotifierConsumerState extends State<ChangeNotifierConsumer> {
  @override
  void initState() {
    super.initState();
    widget.model.addListener(_listener);
  }

  @override
  void dispose() {
    widget.model.removeListener(_listener);
    super.dispose();
  }

  void _listener() {
    print('setstate');
    setState(() {});
  }

  @override
  Widget build(BuildContext context) => widget.builder(context);
}

abstract class Model with ChangeNotifier {

}

class TestModel extends Model {
  String _id;
  String _name;


  TestModel(this._id, this._name);

  get id => _id;
  get name => _name;

  setId(String id) {
    _id = id;
    notifyListeners();
  }

}

【讨论】:

    猜你喜欢
    • 2020-10-28
    • 1970-01-01
    • 2022-11-18
    • 2023-01-26
    • 2021-10-17
    • 2022-01-11
    • 2019-08-18
    • 2020-08-01
    • 2020-10-19
    相关资源
    最近更新 更多