具有共享首选项的Flutter保存列表

时间:2019-12-09 10:06:49

标签: listview flutter sharedpreferences

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

E / flutter(10074):[ERROR:flutter / lib / ui / ui_dart_state.cc(148)]未处理的异常:NoSuchMethodError:方法'add'在null上调用。

E / flutter(10074):接收方:空

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();
                },
              ),
            ],
          );
        });
  }
}

1 个答案:

答案 0 :(得分:0)

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

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

您可以执行以下操作-

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

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

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

希望这会有所帮助!

此外,您不应该在setState()方法内直接调用build(),否则可能会出错,因此也可以将以下代码移到initState()内。

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

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