【问题标题】:Dynamic List in Flutter using SharedPreferencesFlutter 中使用 SharedPreferences 的动态列表
【发布时间】:2021-07-18 12:53:21
【问题描述】:

您好,我正在尝试制作一个应用程序,我可以在其中存储用户输入的数据,例如这个。我的任务是使用 SharedPreferences 来存储数据。

我使用 SharedPreferences 将数据保存在列表中

saveData() async {
List<String> itemData = [];
itemData.add(fstcontroller.text);
itemData.add(sndcontroller.text);
itemData.add(trdcontroller.text);
itemData.add(fthcontroller.text);

SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setStringList("item", itemData);
}

我有两个问题, 第一个问题:每当我单击“显示购物车”按钮时,它都会显示这个

我不想这样显示,我只想显示“物品品牌”,其余的不会显示。 然后,如果我单击单元格,它将在第三个屏幕中显示项目的完整详细信息。

这是第二屏

class SecondScreen extends StatefulWidget {
    @override
    State createState() => new DynamicList();
 }

class DynamicList extends State<SecondScreen> {
  List<String> listItems = [];

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

 getUser() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    var itemData = prefs.getStringList("item");
    setState(() {
      listItems = itemData;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: Column(
        children: <Widget>[
          Expanded(
            child: ListView.builder(
                itemCount: listItems.length, itemBuilder: buildList),
          )
        ],
      ),
    );
  }

  Widget buildList(BuildContext context, int index) {
    return Container(
      margin: EdgeInsets.all(4),
      decoration: BoxDecoration(
          border: Border.all(
            color: Colors.black,
            width: 2,
          ),
          borderRadius: BorderRadius.circular(5)),
      child: ListTile(
        title: Text(listItems[index]),
      ),
    );
  }
  }

第二个问题:每当我添加多个数据时,数据不会堆叠。它只替换数据。

【问题讨论】:

    标签: flutter dart sharedpreferences


    【解决方案1】:

    我认为您需要重新考虑如何存储和读取数据。

    现在您正在“item”键下存储四个字段的列表,因此每次存储数据时,您都会通过将 4 个 item 字段放入列表中来删除“item”。

    虽然我不确定共享首选项是否是最佳选择,但您可以执行以下操作: 将fours字段作为json序列化并将每个json字符串存储在您的列表中。

    对于第二个问题, 存储时,您应该首先检索现有列表并更新该列表,然后再将其存储回来。

    var itemData = prefs.getStringList("item")

    比将新项目添加到列表中:

    itemData.add(newItem)

    存储更新的列表

    prefs.setStringList("item", itemData);

    现在,当您检索列表时,您将检索您的 json 字符串

    使用 json import 'dart:convert'; 然后使用 jsonDecode(stringJson) 从共享首选项中的 listItem 中取回 kson,并使用 jsonEncode(jsonObject) 在存储对象之前将其编码为字符串。

    对于第一个问题,一旦有了 json,就可以访问如下字段: jsonItem['brand']

    Ps 我在我的智能手机上,我无法为你编写完整的代码。以后可能会

    编辑:所以现在我回家了。 对于 json 对象以最小化修改您的代码(未测试):

    saveData() async {
    final Map<String, String> item = Map<String, String>();
    item['brand'] = fstcontroller.text;
    item['size'] = sndcontroller.text);
    item['quantity'] = trdcontroller.text);
    item['color'] = fthcontroller.text);
    
    SharedPreferences prefs = await SharedPreferences.getInstance();
    List<String> cart = prefs.getStringList("cart");
    if (cart == null) cart = [];
    cart.add(jsonEncode(item));
    prefs.setStringList("cart", cart);
    }
    

    然后您的第二个屏幕的代码变为(再次未测试 - 我的更改已被注释):

    import 'dart:convert';
    
    import 'package:flutter/material.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    
    class SecondScreen extends StatefulWidget {
      @override
      State createState() => new DynamicList();
    }
    
    class DynamicList extends State<SecondScreen> {
    // I changed the type of your list
      List<Map<String, String>> listItems = [];
    
      @override
      void initState() {
        super.initState();
        getUser();
      }
    
      getUser() async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
    //I chaged these lines to retrieve the cart instead
        final cart = prefs.getStringList("cart")!;
        setState(() {
    //convert the string cart List back to a list of objects:
          cart.forEach((item) {
            listItems.add(jsonDecode(item));
          });
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          body: Column(
            children: <Widget>[
              Expanded(
                child: ListView.builder(
                    itemCount: listItems.length, itemBuilder: buildList),
              )
            ],
          ),
        );
      }
    
      Widget buildList(BuildContext context, int index) {
        return Container(
          margin: EdgeInsets.all(4),
          decoration: BoxDecoration(
              border: Border.all(
                color: Colors.black,
                width: 2,
              ),
              borderRadius: BorderRadius.circular(5)),
          child: ListTile(
    // Only use the 'brand' field as title of your list
            title: Text(listItems[index]['brand']!),
          ),
        );
      }
    }
    

    【讨论】:

    • 第二个问题解决了,谢谢!第一个问题,不知道把json放在代码的什么地方。
    • 好的 @ShojiYamada 我修改了您的代码,并建议使用 jsonEncode / Decode。我没有测试代码,所以需要更多的调整
    • 我也没有真正测试它并添加了一些非空断言以快速通过它......所以请确保这与您的用例相关
    • 您好,先生,我尝试应用代码,但是当我单击“添加到购物车”按钮时它会引发错误。 dubug控制台说:未处理的异常:NoSuchMethodError:方法'add'在null上被调用。我尝试寻找解决方案,但找不到任何解决方案。我一直在尝试不同的东西,但它不起作用。 (我猜这个错误来自 saveData 函数)。
    • 正如我告诉你的那样,我真的没有测试代码。错误来自这样一个事实,即对于第一项,共享首选项中的列表尚不存在。您应该检查收到的值是否为空。我更新代码
    【解决方案2】:

    使用映射在共享首选项Not List 中存储值。

    SharedPreferences shared_User = await SharedPreferences.getInstance();
                Map decode_options = jsonDecode(jsonString);
                String user = jsonEncode(User.fromJson(decode_options));
                shared_User.setString('user', user);
    
    SharedPreferences shared_User = await SharedPreferences.getInstance();
                Map userMap = jsonDecode(shared_User.getString('user'));
                var user = User.fromJson(userMap);
    
        class User {
          final String name;
          final String age;
    
          User({this.name, this.age});
    
          factory User.fromJson(Map<String, dynamic> parsedJson) {
            return new User(
                name: parsedJson['name'] ?? "",
                age: parsedJson['age'] ?? "");
          }
    
          Map<String, dynamic> toJson() {
            return {
              "name": this.name,
              "age": this.age
            };
          }
        }
    

    【讨论】:

      【解决方案3】:

      对于第一个问题,您的“共享首选项”可以保护您添加到“项目数据”中的所有数据。您需要访问“项目数据”以仅使用您保存的属性名称选择品牌。第二个问题我还没搞清楚

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-02
        • 2020-06-02
        • 1970-01-01
        • 2021-04-20
        • 2021-01-16
        相关资源
        最近更新 更多