Флаттер: несколько экземпляров общих настроек? - PullRequest
0 голосов
/ 19 апреля 2020

У меня проблема с SharedPreferences и несколькими модулями, которые я генерирую на форме, используя ListView.builder

Форма в основном запрашивает некоторые данные родителей и детали их дочерних элементов - по умолчанию форма предполагает, что родитель имеет одного дочернего элемента, но можно добавить еще несколько, нажав кнопку. ChildModule имеет возможность «закрывать», но при «повторном открытии» данные не сохраняются, поэтому, используя SharedPreferences , он отлично работает с одним дочерним элементом, но после добавления второго дочернего элемента, кажется, создавать несколько экземпляров SharedPreferences .

Я вырезал все, чтобы показать, чего я пытаюсь достичь. ПРИМЕЧАНИЕ: это используется в качестве веб-приложения, если оно имеет значение.

О, и ChildModule должен иметь свое собственное состояние, поскольку у него есть виджет, который требует его (не показан)

ЗАПРОС ФОРМА

final GlobalKey<FormBuilderState> _enquiryFormKey = GlobalKey<FormBuilderState>();

class EnquiryForm extends StatefulWidget {
  static List<int> numberOfChildren = [1];
  @override
  _EnquiryFormState createState() => _EnquiryFormState();
}


class _EnquiryFormState extends State<EnquiryForm> {
  int defaultNumberOfChildren = 1;

  removeModule(){
    setState(() {});
  }



  @override
  Widget build(BuildContext context) {
    return FormBuilder(
        key: _enquiryFormKey,
        child: Column(
          children: <Widget>[
            Row(
              children: <Widget>[
                Expanded(
                  child: CustomTextField(
                    label: 'Parent First Name',
                    isRequired: true,
                  ),
                ),
             ), 
            //ChildModuleList
            ListView.builder(
              shrinkWrap: true,
                itemCount: EnquiryForm.numberOfChildren.length,
                itemBuilder: (context,int index){
                  return ChildModule(EnquiryForm.numberOfChildren[index], removeModule);
                }
            ),
            SizedBox(height: 20,),
            Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                ThemedButton(
                    onPressed: (){
                      setState(() {
                        defaultNumberOfChildren++;
                        EnquiryForm.numberOfChildren.add(defaultNumberOfChildren);
                      });
                    },
                    child: Text(
                      'Add Additional Child',
                      style: TextStyle(color: Colors.white),)
                ),
                SizedBox(width: 10,),
                ThemedButton(
                    onPressed: (){},
                    child: Text('Enquire Now', style: TextStyle(color: Colors.white),))
              ],
            )
          ],
        ));
  }
}

МОДУЛЬ РЕБЕНКА

class ChildModule extends StatefulWidget {
  final int number;
  final Function() callback;
  ChildModule(this.number,this.callback);

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

class _ChildModule extends State<ChildModule> {
  SharedPreferences childModuleData;
  String firstName;
  bool loading = true;
  bool isOpen;

  @override
  void initState() {
    print('this module number is ${widget.number}');
    _spInstance();
    isOpen = true;
    super.initState();
  }

  Future<void> _spInstance() async {
    if(childModuleData == null && widget.number == 1) {
      childModuleData = await SharedPreferences.getInstance();
      print('got instance');
    } else {
      print('broken');
      print(childModuleData);
    };
    String _testValue = childModuleData.getString('Child First Name');
    if(_testValue == null){
      childModuleData.setString('Child First Name', '');
      loading = false;
    } else {
      childModuleData.clear();
      _spInstance();
    }
  }



  @override
  Widget build(BuildContext context) {
    return loading ? Loading() : Column(
      children: <Widget>[
        GestureDetector(
          onTap: () {
            setState(() {
              if (isOpen == false) {
                isOpen = true;
              } else {
                isOpen = false;
              }
            });
          },
          child: Container(
            height: 40,
            padding: EdgeInsets.only(left: 10, right: 10),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.all(Radius.circular(4.0)),
              color: Colors.blue[50],
            ),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Text(
                  'Child Details',
                  style: TextStyle(color: Colors.blue[300], fontSize: 16),
                ),
                Row(
                  children: <Widget>[
                    isOpen
                        ? Icon(
                            Icons.arrow_drop_down,
                            size: 30,
                          )
                        : Transform.rotate(
                            angle: math.pi / 2,
                            child: Icon(
                              Icons.arrow_drop_down,
                              size: 30,
                            ),
                          ),
                    widget.number > 1
                        ? IconButton(icon: Icon(Icons.clear), onPressed: () async {
                          await FormFunctions().removeModule(widget.number, EnquiryForm.numberOfChildren);
                          widget.callback();
                    })
                        : Container(),
                  ],
                ),
              ],
            ),
          ),
        ),
        AnimatedContainer(
          duration: Duration(seconds: 2),
          curve: Curves.fastOutSlowIn,
          padding: EdgeInsets.fromLTRB(10, 5, 10, 5),
          height: isOpen ? null : 0,
          decoration: BoxDecoration(
            border: Border.all(color: Colors.grey[300]),
            borderRadius: BorderRadius.all(Radius.circular(4.0)),
          ),
          child: Column(
            children: <Widget>[
              Row(
                children: <Widget>[
                CustomTextField(
                      label: fieldFirstName,
                      isRequired: true,
                      initalValue: childModuleData.getString(fieldFirstName) ?? '',
                      onChanged: (value){
                        childModuleData.setString(fieldFirstName, value);
                      },
                    ),
                ],
              ),
            ],
          ),
        ),
      ],
    );
  }
}

ОШИБКА КОНСОЛИ ПОСЛЕ ВТОРОГО МОДУЛЯ СОЗДАНА

Launching lib/main.dart on Chrome in debug mode...
Syncing files to device Chrome...
Debug service listening on ws://127.0.0.1:58490/EkMAy9CGY74=
Debug service listening on ws://127.0.0.1:58490/EkMAy9CGY74=
this module number is 1
got instance
Instance of 'SharedPreferences'
null
this module number is 2 //Number 2 Module is created
broken
null
null
TypeError: Cannot read property 'getString' of null
    at child_module._ChildModule.new._spInstance$ (http://localhost:58433/packages/webenrol/shared/widgets/day_button.dart.lib.js:3704:47)
    at _spInstance$.next (<anonymous>)
    at runBody (http://localhost:58433/dart_sdk.js:43121:34)
    at Object._async [as async] (http://localhost:58433/dart_sdk.js:43149:7)
    at child_module._ChildModule.new.[_spInstance] (http://localhost:58433/packages/webenrol/shared/widgets/day_button.dart.lib.js:3694:20)
    at child_module._ChildModule.new.initState (http://localhost:58433/packages/webenrol/shared/widgets/day_button.dart.lib.js:3689:24)
    at framework.StatefulElement.new.[_firstBuild] (http://localhost:58433/packages/flutter/src/widgets/widget_span.dart.lib.js:41219:58)
    at framework.StatefulElement.new.mount (http://localhost:58433/packages/flutter/src/widgets/widget_span.dart.lib.js:12605:24)
    at framework.SingleChildRenderObjectElement.new.inflateWidget (http://localhost:58433/packages/flutter/src/widgets/widget_span.dart.lib.js:11420:16)

1 Ответ

0 голосов
/ 19 апреля 2020

в вашем случае проблема заключается в уровне записи данных в общих настройках. Одним из решений было бы добавить номер виджета в ключ, чтобы сохранить как это (await SharedPreferences.getInstance()).setString("Your Key${widgetNumber}"); и редактировать вашу функцию _spInstance

class ChildModule extends StatefulWidget {
  final int number;
  final Function() callback;
  ChildModule(this.number,this.callback);

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

class _ChildModule extends State<ChildModule> {
  SharedPreferences childModuleData;
  ...

  Future<void> _spInstance() async {
    if(childModuleData == null) {
      childModuleData = await SharedPreferences.getInstance();
      print('got instance');
    }
    String _testValue = childModuleData.getString('Child First Name${widget.number}');
    //NB: do not clear data on chlidModuleData any more.
    ...

  }

  ...

}
...