在颤振中在 initstate() 之前调用了dependOnInheritedElement()

Posted

技术标签:

【中文标题】在颤振中在 initstate() 之前调用了dependOnInheritedElement()【英文标题】:dependOnInheritedElement() was called before initstate() in flutter 【发布时间】:2020-06-07 08:38:19 【问题描述】:

我目前在获取 Provider' value ininitstate 时遇到问题。

我想在 Appbar 的下拉列表和正文的其他部分设置默认值。但我收到一条错误消息,提示 dependOnInheritedElement() was called before initstate() in flutter

我的完整代码如下

main.dart

import 'package:test_eoil/model/button_data.dart';
import 'package:test_eoil/model/output_data.dart';
import 'screen/screen.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';


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

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MultiProvider(providers: [
//      ChangeNotifierProvider<ChordData>(create: (context) => ChordData()),
      ChangeNotifierProvider<OutputData>(create: (context) => OutputData()),
      ChangeNotifierProvider<ButtonData>(create: (context) => ButtonData())
    ],
      child: MaterialApp(
        home: Screen(),
      ),
    );
  

屏幕文件夹中的screen.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_eoil/model/button_data.dart';
import 'package:test_eoil/model/output_data.dart';


class Screen extends StatefulWidget 
  @override
  _ScreenState createState() => _ScreenState();


class _ScreenState extends State<Screen> 

  Widget dropdownWidget() 
    return DropdownButton<Button>(
      items: Provider.of<ButtonData>(context).buttons.map((Button value) 
        return new DropdownMenuItem<Button>(
          value: value,
          child: new Text(value.type.toString()),
        );
      ).toList(),
      onChanged: (Button newValue) 
        Provider.of<ButtonData>(context).setSelectedItem(newValue);
      ,
      value: Provider.of<ButtonData>(context).selectedButton,
    );
  

  @override
  void initState() 
    Provider.of<ButtonData>(context).selectedButton = Provider.of<ButtonData>(context).buttons.first;
    super.initState();
  


  @override
  Widget build(BuildContext context) 
    return Consumer<OutputData>(
        builder: (context, outputData, child) => Scaffold(
            appBar: AppBar(
              title: Text("$Provider.of<ButtonData>(context).selectedButton"), // new Text(widget.title), // "$Provider.of<ButtonData>(context).selectedButton.key"
              actions: <Widget>[
                dropdownWidget(),
              ],
            ),
            body: Column(
              children: <Widget>[
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  mainAxisSize: MainAxisSize.max,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    Container(
                      alignment: Alignment.centerRight,
                      padding: new EdgeInsets.symmetric(
                          vertical: 24.0, horizontal: 12.0),
                      child: outputData.outputs[0].output3.length > 2
                          ? Text(
                          '$outputData.outputs[0].output3.substring(1, outputData.outputs[0].output3.length-1)',
                          style: TextStyle(
                            fontSize: 35.0,
                            fontWeight: FontWeight.bold,
                          ))
                          : Text('$outputData.outputs[0].output3',
                          style: TextStyle(
                            fontSize: 35.0,
                            fontWeight: FontWeight.bold,
                          )),
                    ),
                    Container(
                      alignment: Alignment.centerRight,
                      padding: new EdgeInsets.symmetric(
                          vertical: 24.0, horizontal: 12.0),
                      child: outputData.outputs[0].output2.length > 2
                          ? Text(
                          '$outputData.outputs[0].output2.substring(1, outputData.outputs[0].output2.length-1)',
                          style: TextStyle(
                            fontSize: 35.0,
                            fontWeight: FontWeight.bold,
                          ))
                          : Text('$outputData.outputs[0].output2',
                          style: TextStyle(
                            fontSize: 35.0,
                            fontWeight: FontWeight.bold,
                          )),
                    ),
                    Container(
                      alignment: Alignment.centerRight,
                      padding: new EdgeInsets.symmetric(
                          vertical: 24.0, horizontal: 12.0),
                      child: Text('$outputData.outputs[0].output1',  //  outputData.outputs[0].output1
                          style: TextStyle(
                            fontSize: 35.0,
                            fontWeight: FontWeight.bold,
                          )),
                    ),
                  ],
                ),
                Expanded(
                  child: new Divider(),
                ),
                Column(children: [
                  Row(children: [
                    buildButton("CLEAR"),
                    buildButton(""),
                    buildButton("PLAY"),
                    //                    buildButton("/")
                  ]),
                ])
              ],
            )));
  



  Widget buildButton(String buttonText) 
    return new Expanded(
      child: new OutlineButton(
        padding: new EdgeInsets.all(30.0),
        child: new Text(
          buttonText,
          style: TextStyle(fontSize: 20.0),
        ),
        onPressed: () => print("test"),
      ),
    );
  


button_data.dart 在模型文件夹中

import 'package:flutter/foundation.dart';
//import 'dart:collection';

class Button 
  final int id;
  final String type;
  final String numberone;
  final String numbertwo;
  final String numberthree;

  Button(this.id, this.type, this.numberone, this.numbertwo, this.numberthree);




class ButtonData extends ChangeNotifier 
  List<Button> _buttons = [
    Button(
      type: "A",
      numberone: "1",
      numbertwo: "2",
      numberthree: "3",
    ),
    Button(
      type: "B",
      numberone: "A",
      numbertwo: "B",
      numberthree: "C",
    ),
  ];

  List<Button> get buttons => _buttons;
  Button _selectedButton;
  Button get selectedButton => _selectedButton;

  set selectedButton(Button button) 
    _selectedButton = button;
    notifyListeners();
  


  void setSelectedItem(Button s) 
    _selectedButton = s;
    notifyListeners();
  

  Button getKey(String value) 
    return _buttons
        .where((button) => button.type == value).first;
  

  String getNumberOne(String value) 
    return _buttons
        .where((button) => button.type == value)
        .map((button) => (button.numberone))
        .toString();
  

  String getNumberTwo(String value) 
    return _buttons
        .where((button) => button.type == value)
        .map((button) => (button.numbertwo))
        .toString();
  

  String getNumberThree(String value) 
    return _buttons
        .where((button) => button.type == value)
        .map((button) => (button.numberthree))
        .toString();
  


output_data.dart 在模型文件夹中

import 'package:flutter/foundation.dart';


class Output 

  final int id;
  String output1;
  String output2;
  String output3;

  Output(this.id, this.output1, this.output2, this.output3);




class OutputData extends ChangeNotifier 

  List<Output> _outputs = [
    Output(output1: 'Hello', output2: 'Hi', output3: 'Nice'),
    Output(output1: 'Haha', output2: 'Bye', output3: 'Sad'),
  ];

  List<Output> get outputs 
    return _outputs;
  




说实话,如果可能的话,我想让它在没有initstate() 的情况下工作(我听说提供者模式不需要stful)

我提出initstate() 的原因是这是唯一的解决方案(据我所知)在提供程序中设置默认值。

希望大家帮帮我!


通过在button_data.dart 中添加 Button_data 构造函数解决了问题。

ButtonData () 
    _selectedButton = _buttons.first;
  

【问题讨论】:

【参考方案1】:

我在之前的回答中还提到,Provider.of(context) 应该在小部件树中使用,而在 build() 方法之外的任何东西都不在小部件树中。但是如果还想用的话,就需要把listen参数设置为false

像这样:

@override
  void initState() 
    Provider.of<ButtonData>(context, listen: false).selectedButton = Provider.of<ButtonData>(context, listen: false).buttons.first;
    super.initState();
  

但正如您在问题中提到的,您不想使用 initState 设置默认值。在每种编程语言中,当您声明一个带有值的变量时,该值将成为它的初始/默认值,您可以稍后更改它。

您可以在ButtonData 类中编辑以下内容,而不是使用initState

//Remove this.
List<Button> get buttons => _buttons;
  Button _selectedButton;
  Button get selectedButton => _selectedButton;

//Instead, Use this.
List<Button> get buttons => _buttons;
Button _selectedButton = _buttons.first;
Button get selectedButton => _selectedButton;

//This will declare the `selectedButton` variable with a default value.
//Happy coding! :)

【讨论】:

我在initial value中将listen参数设置为false。返回相同的错误。你可以检查一下,因为我上传了完整的代码。 第二种方式——用button_data.dart中的值声明一个变量。——这就是我最初的意图。但是当我用你所说的值声明一个变量时,错误返回Only static members can be accessed in initializers。我上传了完整的代码,你也可以检查一下。 如果可能,我想修复第二个问题only static member...。但据我所知,这很难解决。这就是为什么我试图以不同的方式绕过它。 问题已解决。我刚刚编辑了我的块。真的感谢您看我的问题。 @BasedMusa

以上是关于在颤振中在 initstate() 之前调用了dependOnInheritedElement()的主要内容,如果未能解决你的问题,请参考以下文章

如何在 initState 方法中访问颤振块?

将文档中的值从数据库保存到 initState 值的颤振问题

未处理的异常:在 _ScreenState.initState() 完成之前调用了 inheritFromWidgetOfExactType(_LocalizationsScope) 或 inheri

l1n在initState之前调用

Flutter:异步任务在“initState()”中无法按预期工作

为什么在下面的代码中在向量中打印值之前调用析构函数