【问题标题】:Flutter local persistence of Maps using shared preferences使用共享首选项颤动地图的本地持久性
【发布时间】:2021-09-19 18:32:04
【问题描述】:

我是一名业余编码人员,正在做我的第一个 Flutter 项目。这是一个简单的每日单词应用程序,人们可以在其中写下单词的句子来记住它们。然后,该应用程序将这些句子存储在 ExpandedTile 中,其中单词作为标题,句子作为字幕。但是,我在手机上本地保存这些信息时遇到了一些问题。我已经修改了很多选项,并尝试了路径提供程序和共享首选项。这里的 words 对象是一个包含所有单词和含义的 Map,而 Savedwords 是一个以单词作为键,句子作为值的映射。当前使用共享首选项显示此错误:

    E/flutter ( 1223): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: type String' is not a subtype of type 'List<String>'
E/flutter ( 1223): #0      _SavedprefState.addString.<anonymous closure>
package:to_dolist/widgets/sharedpreflist.dart:22
E/flutter ( 1223): #1      _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:397:8)
E/flutter ( 1223): #2      _SavedprefState.addString
package:to_dolist/widgets/sharedpreflist.dart:22
E/flutter ( 1223): <asynchronous suspension>
E/flutter ( 1223):
E/flutter ( 1223): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: NoSuchMethodError: The getter 'iterator' was called on null.
E/flutter ( 1223): Receiver: null
E/flutter ( 1223): Tried calling: iterator
E/flutter ( 1223): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
E/flutter ( 1223): #1      _SavedprefState.getString
package:to_dolist/widgets/sharedpreflist.dart:30
E/flutter ( 1223): <asynchronous suspension>
E/flutter ( 1223):

我希望你们可以使用下面给出的代码帮助解决这个错误。如果这有助于为这个持久性问题获得更有效的解决方案,我在这里提供了更多必要的代码。我已经被这个问题困扰了几个月了,如果你能在这里给出编码的解决方案,我真的会帮助我。这是主要的 dart 文件

import 'package:flutter/material.dart';
import 'package:to_dolist/screens/HomePage.dart';
import './words.dart';
import './widgets/all.dart';
import './screens/secondscreen.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);
  @override
  State<StatefulWidget> createState() {
    return MyAppState();
  }
}

class MyAppState extends State<MyApp> {
  var currentIndex = 0;
  final saveword = TextEditingController();

  var index = 0;
  void nextword() {
    saveword.clear();
    setState(() {
      if (index == words.length) {
        //index == words.length;
      } else {
        index++;
      }
    });
  }

  void dispose() {
    // Clean up the controller when the widget is disposed.
    saveword.dispose();
    super.dispose();
  }

  void prevword() {
    saveword.clear();
    setState(() {
      if (index == 0) {
      } else {
        index--;
      }
    });
    //return index;
  }

  void onTapped(int index) {
    setState(() {
      currentIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    final List<Widget> screens = [
      HomePage(index, nextword, prevword, saveword),
      SecondPage(saveword)
    ];
    return MaterialApp(
        theme: ThemeData(),
        home: Builder(
            builder: (context) => Scaffold(
                  backgroundColor: Colors.grey[850],
                  appBar: AppBar(
                    iconTheme: IconThemeData(color: Colors.green),
                    title: RichText(
                      textAlign: TextAlign.left,
                      text: TextSpan(
                        style: TextStyle(
                          color: Colors.white,
                          fontSize: 50,
                        ),
                        children: <TextSpan>[
                          TextSpan(text: 'Word of \n     ', style: TextStyle()),
                          TextSpan(
                              text: '     The Day',
                              style: TextStyle(fontWeight: FontWeight.bold)),
                        ],
                      ),
                    ),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.vertical(
                        bottom: Radius.circular(30),
                      ),
                    ),
                    toolbarHeight: 130,
                    centerTitle: true,
                    elevation: 4,
                    backgroundColor: Colors.grey,
                  ),
                  body: screens[currentIndex],
                  bottomNavigationBar: BottomNavigationBar(
                    elevation: 100,
                    //backgroundColor: Colors.grey,
                    type: BottomNavigationBarType.shifting,
                    currentIndex: currentIndex,
                    items: const <BottomNavigationBarItem>[
                      BottomNavigationBarItem(
                          icon: Icon(Icons.today),
                          label: 'Word of The Day',
                          backgroundColor: Colors.grey),
                      BottomNavigationBarItem(
                          icon: Icon(Icons.list),
                          label: 'History',
                          backgroundColor: Colors.grey),
                    ],
                    onTap: onTapped,
                  ),
                  floatingActionButtonLocation:
                      FloatingActionButtonLocation.miniCenterDocked,
                  floatingActionButton: Fab(saveword, index),
                )));
  }
}

这是主页:

import 'package:flutter/material.dart';
import 'package:to_dolist/widgets/all.dart';

@override
class HomePage extends StatelessWidget {
  //const ({ Key? key }) : super(key: key);

  final int index;
  final Function nextword;
  final Function prevword;
  final control;
  HomePage(this.index, this.nextword, this.prevword, this.control);

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        children: <Widget>[
          SizedBox(
            height: 20,
            width: 500,
          ),
          Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(12),
              color: Colors.grey,
            ),
            child: WordColumn(index),
            alignment: Alignment.center,
            margin: new EdgeInsets.only(left: 20.0, right: 20.0, top: 20.0),
            padding: new EdgeInsets.all(20.0),
          ),
          Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(12),
              color: Colors.grey,
            ),
            alignment: Alignment(0.0, 0.0),
            margin: new EdgeInsets.all(20.0),
            padding: new EdgeInsets.all(35.0),
            child: TextField(
              style: TextStyle(color: Colors.white),
              controller: control,
              onChanged: (text) => {},
              keyboardType: TextInputType.multiline,
              minLines: 2,
              maxLines: 30,
            ),
          ),
          NavigateWords(nextword, prevword),
          SizedBox(
            height: 50,
            width: double.infinity,
          ),
          /*ElevatedButton(
            child: Text('history'),
            onPressed: Storage.readCounter ,
          )*/
        ],
      ),
    );
  }
}

还有第二页的dart文件:

import 'package:flutter/material.dart';
import 'package:to_dolist/words.dart';
import './fab.dart';
import 'package:shared_preferences/shared_preferences.dart';

class Savedpref extends StatefulWidget {
  TextEditingController control;
  Savedpref(this.control);
  //const Savedpref({ Key? key }) : super(key: key);

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

class _SavedprefState extends State<Savedpref> {
  Future<SharedPreferences> savedlist = SharedPreferences.getInstance();
  var written, read, values;
  List<Widget> savedhistory = [];
  Future<Null> addString() async {
    final SharedPreferences prefs = await savedlist;
    Fab.savedwords
        .forEach((key, value) => {prefs.setStringList(key, value)});
    setState(() {});
  }

  Future<Null> getString() async {
    final SharedPreferences prefs = await savedlist;
    var keys = prefs.getKeys();
    keys.forEach((element) => {read.add(element)});
    for (var k in read) {
      values.add(prefs.get(k));
    }
    for (var j = 0; j <= keys.length; j++) {
      savedhistory.add(new ExpansionTile(
        title: Text(read[j], style: TextStyle(color: Colors.white)),
        subtitle: Text(words[j].value, style: TextStyle(color: Colors.white)),
        children: [
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(values[j]),
            ],
          )
        ],
      ));
    }
    setState(() {});
    //keys.add(prefs.getKeys());
    //prefs.
  }

  @override
  Widget build(BuildContext context) {
    @override
    void initState() {
      super.initState();
      written = [];
      read = [];
    }

    return Stack(children: [
      ListView.separated(
          reverse: true,
          shrinkWrap: true,
          separatorBuilder: (context, i) => Container(
                //color: Colors.greenAccent,
                width: double.infinity,
                height: 8,
              ),
          itemCount: savedhistory.length,
          itemBuilder: (context, i) => Dismissible(
                key: UniqueKey(),
                onDismissed: (direction) {
                  setState(() {
                    savedhistory.removeAt(i);
                  });
                },
                child: Container(
                  margin: EdgeInsets.all(10),
                  padding: EdgeInsets.all(5),
                  decoration: BoxDecoration(
                      color: Colors.grey,
                      borderRadius: BorderRadius.all(Radius.circular(20))),
                  child: savedhistory[i],
                  //padding: EdgeInsets.all(8.0),
                ),
                /* read == null
            ? []
            : read.map((e) => ExpansionTile(
                  title: Text(e),
                  subtitle: Text(e),
                )), */
              )),
      Align(
        alignment: Alignment.bottomRight,
        child: GestureDetector(
            onLongPress: () => getString(),
            child: FloatingActionButton(
              child: Icon(Icons.replay_outlined),
              onPressed: addString,
            )),
      )
    ]);
  }
}

这是浮动操作按钮 (Fab) 小部件代码:

import 'package:to_dolist/words.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:to_dolist/widgets/sharedpreflist.dart';
//import 'dart:convert';

class Fab extends StatelessWidget {
  static List history = <Widget>[];
  static Map savedwords = Map();
  /* void save1() {
    savedwords[words[index].key] = control.text;
    Storage.writeCounter();
  }*/

  void save() {
    savedwords[words[index].key] = control.text;
    //addString();
    //print(savedwords);*/
    /*history.add(new ExpansionTile(
      title: Text(
        words[index].key,
        style: TextStyle(color: Colors.white),
      ),
      subtitle: Text(words[index].value, style: TextStyle(color: Colors.white)),
      expandedCrossAxisAlignment: CrossAxisAlignment.start,
      backgroundColor: Colors.grey,
      children: [
        Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(control.text),
          ],
        )
      ],
      //tileColor: Colors.white,
      //shape: RoundedRectangleBorder(
      //side: BorderSide(width: 1), borderRadius: BorderRadius.circular(20)),
    )); */
  }

  //final Function save;
  final int index;
  final control;
  Fab(this.control, this.index);
  @override
  Widget build(BuildContext context) {
    return Container(
      child: FloatingActionButton.extended(
        onPressed: save,
        label: const Text('Save'),
        icon: const Icon(Icons.save),
        backgroundColor: Colors.green[200],
      ),
    );
  }
}

【问题讨论】:

    标签: flutter flutter-dependencies


    【解决方案1】:

    我相信错误来自这里的这个块

     Future<Null> addString() async {
        final SharedPreferences prefs = await savedlist;
        Fab.savedwords
            .forEach((key, value) => {prefs.setStringList(key, value)});
        setState(() {});
      }
    

    在您的SavePrefs 状态。

    准确地说是这条线

    Fab.savedwords
            .forEach((key, value) => {prefs.setStringList(key, value)});
    

    我相信您正在遍历字符串列表并希望将每个字符串保存到本地存储中。但是您调用了 sharedpreferences 的 setStringList 函数。此函数要求 value 是字符串列表,但由于您的循环,您实际上传递的 value 是单个字符串。 因此错误

    未处理的异常:String 类型不是“List”类型的子类型。

    它的意思是你不能将字符串作为参数传递给正在寻找字符串列表的函数(即“name”与 ['name'] 不同)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-16
      • 2014-08-08
      • 2021-05-31
      • 2019-12-17
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      相关资源
      最近更新 更多