【问题标题】:Flutter: Subtype Error when creating an widget with genericsFlutter:使用泛型创建小部件时出现子类型错误
【发布时间】:2020-05-15 09:58:24
【问题描述】:

我正在为我的应用程序使用扩展 ChangeNotifier 的视图模型。为了使用它们,我正在尝试实现一个通用的基本小部件:


    class BasePageWidget<ViewModelType extends ChangeNotifier>
        extends StatefulWidget {
      final Function(ViewModelType vm) init;
      final Widget Function(BuildContext context, ViewModelType vm) builder;
      final ViewModelType _vm = sl.get<ViewModelType>();

      BasePageWidget({Key key, this.init, this.builder}) : super(key: key);

      @override
      _BasePageWidgetState createState() => _BasePageWidgetState<ViewModelType>();
    }

    class _BasePageWidgetState<ViewModelType extends ChangeNotifier>
        extends State<BasePageWidget> {
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider<ViewModelType>.value(
          value: widget._vm,
          child: Consumer<ViewModelType>(
            builder: (context, _vm, child) => widget.builder(context, widget._vm),
          ),
        );
      }

      @override
      void initState() {
        if (widget.init != null) {
          widget.init(widget._vm);
        }
        super.initState();
      }
    }

基本小部件有一个类型参数,并使用 get_it 包的服务定位器获取视图模型的实例。

但是当我尝试运行应用程序时,使用小部件时:

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: BasePageWidget<ViewModel>(
        init: (vm) => vm.setTitle("Set init State"),
        builder: (context, vm) => FlatButton(
          onPressed: () {
            vm.setTitle("State2");
          },
          child: Text(vm.text),
        ),
      ),
    );
  }
}

Flutter 抛出运行时错误:

flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following assertion was thrown building Builder:
flutter: type '(ViewModel) => void' is not a subtype of type '(ChangeNotifier) => dynamic'
flutter:
flutter: The relevant error-causing widget was:
flutter:   MaterialApp 
lib/main.dart:15
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0      _BasePageWidgetState.initState 
package:viewmodel_test/base_widget.dart:31
flutter: #1      StatefulElement._firstBuild 
package:flutter/…/widgets/framework.dart:4456
flutter: #2      ComponentElement.mount 
package:flutter/…/widgets/framework.dart:4302
flutter: #3      Element.inflateWidget 
package:flutter/…/widgets/framework.dart:3297
flutter: #4      Element.updateChild 
package:flutter/…/widgets/framework.dart:3091
flutter: #5      SingleChildRenderObjectElement.mount 

错误似乎是由函数参数引起的:

final Function(ViewModelType vm) init;
final Widget Function(BuildContext context, ViewModelType vm) builder;

当我将泛型类型 (ViewModelType) 与动态交换时,应用程序运行良好(当然没有类型安全):

final Function(ViewModelType vm) init;
final Widget Function(BuildContext context, ViewModelType vm) builder;

任何想法如何使它与通用参数一起运行?

这是我的视图模型:

class ViewModel extends ChangeNotifier {
  String text = '';

  void setTitle(String text) {
    this.text = text;
    notifyListeners();
  }
}

以及 get_it 设置:

GetIt sl = GetIt.instance;

Future<void> setup() async {
  sl.registerFactory(() => ViewModel());
}

【问题讨论】:

    标签: flutter flutter-provider flutter-change-notifier


    【解决方案1】:

    您可以在下面复制粘贴运行完整代码
    请把State&lt;BasePageWidget&gt;改成State&lt;BasePageWidget&lt;ViewModelType&gt;&gt;

    来自

    class _BasePageWidgetState<ViewModelType extends ChangeNotifier>
        extends State<BasePageWidget> {
    

    class _BasePageWidgetState<ViewModelType extends ChangeNotifier>
    extends State<BasePageWidget<ViewModelType>> {
    

    工作演示

    完整代码

    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    import 'package:get_it/get_it.dart';
    
    class BasePageWidget<ViewModelType extends ChangeNotifier>
        extends StatefulWidget {
      final Function(ViewModelType vm) init;
      final Widget Function(BuildContext context, ViewModelType vm) builder;
      final ViewModelType _vm = sl.get<ViewModelType>();
    
      BasePageWidget({Key key, this.init, this.builder}) : super(key: key);
    
      @override
      _BasePageWidgetState createState() => _BasePageWidgetState<ViewModelType>();
    }
    
    class _BasePageWidgetState<ViewModelType extends ChangeNotifier>
        extends State<BasePageWidget<ViewModelType>> {
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider<ViewModelType>.value(
          value: widget._vm,
          child: Consumer<ViewModelType>(
            builder: (context, _vm, child) => widget.builder(context, widget._vm),
          ),
        );
      }
    
      @override
      void initState() {
        if (widget.init != null) {
          widget.init(widget._vm);
        }
        super.initState();
      }
    }
    
    class ViewModel extends ChangeNotifier {
      String text = '';
    
      void setTitle(String text) {
        this.text = text;
        notifyListeners();
      }
    }
    
    GetIt sl = GetIt.instance;
    
    Future<void> setup() async {
      sl.registerFactory(() => ViewModel());
    }
    
    void main() {
      setup();
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          home: BasePageWidget<ViewModel>(
            init: (vm) => vm.setTitle("Set init State"),
            builder: (context, vm) => Scaffold(
              body: Center(
                child: FlatButton(
                  onPressed: () {
                    vm.setTitle("State2");
                  },
                  child: Text(vm.text),
                ),
              ),
            ),
          ),
        );
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-10-05
      • 1970-01-01
      • 2021-11-03
      • 1970-01-01
      • 2018-04-03
      • 2017-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多