【问题标题】:Flutter save List with shared preferences具有共享首选项的颤振保存列表
【发布时间】:2020-04-02 10:02:47
【问题描述】:

我尝试将字符串列表永久保存到设备中。尝试通过弹出对话框添加列表时,显示以下错误

E/flutter (10074):[错误:flutter/lib/ui/ui_dart_state.cc(148)] 未处理的异常:NoSuchMethodError:在 null 上调用了“add”方法。 p>

E/flutter (10074):接收者:null

E/flutter (10074):尝试调用:add("drinks")

ListView 进一步在打开页面时不显示。 (进入屏幕对话框后会打开)

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class Categories extends StatefulWidget {
  @override
  _CategoriesState createState() => _CategoriesState();
}

class _CategoriesState extends State<Categories> {
  List<String> categoryList = List<String>();
  TextEditingController _textFieldController = TextEditingController();
  int count = 0;

  @override
  Widget build(BuildContext context) {
    if (categoryList == null) {
      setState(() {
        categoryList = ['Food', 'Clothes'];
      });
    }
    _update();
    return Scaffold(
      appBar: AppBar(
        title: Text("Categories"),
      ),
      body: SafeArea(
        child: Container(
          color: Colors.white,
          child: getCategoriesListView(),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          setState(() {
            _displayDialog(context);
          });
        },
      ),
    );
  }

  ListView getCategoriesListView() {
    return ListView.builder(
        itemCount: categoryList.length,
        itemBuilder: (context, int position) {
          return Card(
            color: Colors.white,
            elevation: 2.0,
            child: ListTile(
              title: Text(categoryList[position]),
              trailing: GestureDetector(
                child: Icon(
                  Icons.delete,
                  color: Colors.grey,
                ),
                onTap: () {
                  setState(() {
                    _delete(context, categoryList[position]);
                  });
                },
              ),
            ),
          );
        });
  }

  void _add(BuildContext context, String category) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    categoryList.add(category);
    prefs.setStringList('Categories', categoryList);
    showSnackBar(context, 'Your category was added');
  }

  void _delete(BuildContext context, String category) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    categoryList.remove(category);
    prefs.setStringList('Categories', categoryList);
    showSnackBar(context, 'Your category was removed');
  }

  void _update() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    categoryList = prefs.getStringList('Categories');
  }

  void showSnackBar(BuildContext context, String message) async {
    final snackBar = SnackBar(content: Text(message));
    Scaffold.of(context).showSnackBar((snackBar));
  }

  _displayDialog(BuildContext context) async {
    return showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: Text('Add new category'),
            content: TextField(
              controller: _textFieldController,
            ),
            actions: <Widget>[
              FlatButton(
                child: Text('ADD'),
                onPressed: () {
                  setState(() {
                    String name = _textFieldController.text;
                    print(name);
                    _add(context, name);
                    Navigator.of(context).pop();
                  });
                },
              ),
              FlatButton(
                child: Text('CANCEL'),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              ),
            ],
          );
        });
  }
}

【问题讨论】:

    标签: listview flutter sharedpreferences


    【解决方案1】:

    您应该在initState() 函数中调用_update() 方法而不是build()。现在,每次调用 setState() 时,都会调用 build() 函数,然后调用 update(),因此 categoryList 会被覆盖。

    因此您无法向List 添加新项目。

    你可以这样做 -

    @override
    void initState() {
      super.initState();
      _update();
    }
    

    然后不要在build() 中调用_update() 方法。 但是现在由于我们将 _update() 调用移到了 build() 之外,您将不得不在 _update() 中使用 setState() 以便正确刷新状态。

    void _update() async {
      SharedPreferences prefs = await SharedPreferences.getInstance();
      categoryList = prefs.getStringList('Categories');
    }
    

    希望这会有所帮助!

    另外,你不应该直接在build()方法中调用setState(),你可能会得到一个错误,所以你也可以将下面的代码移动到initState()中。

    //Move this inside initState();
    if (categoryList == null) {
      setState(() {
        categoryList = ['Food', 'Clothes'];
      });
    }
    

    initState() 方法仅在调用 build() 方法之前初始化您的小部件时调用一次。

    【讨论】:

    • 当对话框屏幕打开时出现以下错误════════ Exception caught by widgets library ═══════════════════════════════════════════════════════ The following NoSuchMethodError was thrown building Categories(dirty, dependencies: [_LocalizationsScope-[GlobalKey#ea957], _InheritedTheme], state: _CategoriesState#df48e): The getter 'length' was called on null. Receiver: null Tried calling: length
    • 在检查 categoryList 是 null 之后,您似乎正在调用 _upadte()。仅当不是 null 时,才应将值从 SharedPreferences 分配给 categoryList。
    • 那么我需要如何安排这个 initStat() 1. super.initState() 2. if 子句 3. _update() 对吗? @override void initState() { super.initState(); if (categoryList == null || categoryList.isEmpty) { setState(() { categoryList = ['Food', 'Clothes']; }); } _update(); }
    • 仅当categoryList 为null 或为空时才设置categoryList = prefs.getStringList('Categories'); 内部更新。
    • 在 initState() 中,当列表为空时,我将食物和衣服添加到列表中,然后调用 _update() 函数,然后尝试获取它们保存的数据,但前提是它为空。问题是列表不再为空,因为我在 initState() 中添加了食物和衣服
    猜你喜欢
    • 2021-08-16
    • 2020-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多