Dart jsonEncode给我错误未处理的异常:将对象转换为可编码对象失败

时间:2019-12-29 19:48:53

标签: flutter dart

jsonEncode时出现错误

Unhandled Exception: Converting object to an encodable object failed: Instance of 'WordPair'

我已经阅读了有关json_annotation和json_serializable的信息,但我不知道它们对我的情况有何帮助。当我无法访问“ WordPair”类时,我不知道如何使用它。

在代码中,我们使用english_words软件包获取随机的“ WordPair”。我正在尝试将用户选择的一些喜欢的单词保存到shared_preferences中。但是我不知道如何使列表可序列化。我对Dart和Flutter非常陌生。请帮忙。

import "package:flutter/material.dart";
import "package:english_words/english_words.dart";
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

class RandomWordsState extends State<RandomWords> {
  final _randomWordPairs = <WordPair>[];
  final _savedWordPairs = Set<WordPair>();

  Future<void> _setSavedWordPairs() async {
    List<WordPair> savedWordPairsList = _savedWordPairs.toList();
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString("wordpairs", jsonEncode(savedWordPairsList));
    print(prefs.getString("wordpairs"));
  }

  Future<void> _getSavedWordPairs() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String savedWordPairsString =
        prefs.getString("wordpairs") ?? jsonEncode(<WordPair>[]);
    List<WordPair> savedWordPairsList = jsonDecode(savedWordPairsString);
    print(savedWordPairsList);
    setState(() {
      _randomWordPairs.addAll(savedWordPairsList);
      _savedWordPairs.addAll(savedWordPairsList);
    });
  }

  Widget _buildList() {
    return ListView.builder(
      padding: const EdgeInsets.all(16.0),
      itemBuilder: (context, item) {
        if (item.isOdd) return Divider();

        final index = item ~/ 2;

        if (index >= _randomWordPairs.length) {
          _randomWordPairs.addAll(generateWordPairs().take(10));
        }

        return _buildRow(_randomWordPairs[index]);
      },
    );
  }

  Widget _buildRow(WordPair pair) {
    final alreadySaved = _savedWordPairs.contains(pair);

    return ListTile(
      title: Text(pair.asPascalCase, style: TextStyle(fontSize: 18.0)),
      trailing: Icon(
        alreadySaved ? Icons.favorite : Icons.favorite_border,
        color: alreadySaved ? Colors.red : null,
      ),
      onTap: () {
        setState(() {
          if (alreadySaved) {
            _savedWordPairs.remove(pair);
          } else {
            _savedWordPairs.add(pair);
          }
        });
        _setSavedWordPairs();
      },
    );
  }

  void _pushSaved() {
    Navigator.of(context)
        .push(MaterialPageRoute(builder: (BuildContext context) {
      final Iterable<ListTile> tiles = _savedWordPairs.map((WordPair pair) {
        return ListTile(
            title: Text(pair.asPascalCase, style: TextStyle(fontSize: 16.0)));
      });

      final List<Widget> divided =
          ListTile.divideTiles(context: context, tiles: tiles).toList();

      return Scaffold(
        appBar: AppBar(
          title: Text("Saved WordPairs"),
        ),
        body: ListView(
          children: divided,
        ),
      );
    }));
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("WordPair Generator"),
          actions: <Widget>[
            IconButton(
              icon: Icon(Icons.list),
              onPressed: _pushSaved,
            )
          ],
        ),
        body: _buildList());
  }
}

1 个答案:

答案 0 :(得分:1)

您可以在下面复制粘贴运行完整代码
您需要扩展WordPair并添加toJson()fromJson()

代码段

List<WordPairExt> wordPairExtFromJson(String str) => 
List<WordPairExt>.from(json.decode(str).map((x) => WordPairExt.fromJson(x)));

String wordPairExtToJson(List<WordPairExt> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class WordPairExt extends WordPair {
  String first;
  String second;

  WordPairExt({
    this.first,
    this.second,
  }) : super(first, second);

  factory WordPairExt.fromJson(Map<String, dynamic> json) => WordPairExt(
        first: json["first"],
        second: json["second"],
      );

  Map<String, dynamic> toJson() => {
        "first": first,
        "second": second,
      };
}

工作演示

enter image description here

完整代码

import 'package:flutter/material.dart';
import "package:english_words/english_words.dart";
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';

List<WordPairExt> wordPairExtFromJson(String str) => List<WordPairExt>.from(json.decode(str).map((x) => WordPairExt.fromJson(x)));

String wordPairExtToJson(List<WordPairExt> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class WordPairExt extends WordPair {
  String first;
  String second;

  WordPairExt({
    this.first,
    this.second,
  }) : super(first, second);

  factory WordPairExt.fromJson(Map<String, dynamic> json) => WordPairExt(
        first: json["first"],
        second: json["second"],
      );

  Map<String, dynamic> toJson() => {
        "first": first,
        "second": second,
      };
}

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

class RandomWordsState extends State<RandomWords> {
  final _randomWordPairs = <WordPairExt>[];
  final _savedWordPairs = Set<WordPairExt>();

  Future<void> _setSavedWordPairs() async {
    List<WordPairExt> savedWordPairsList = _savedWordPairs.toList();
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString("wordpairs", wordPairExtToJson(savedWordPairsList));
    print(prefs.getString("wordpairs"));
  }

  Future<void> _getSavedWordPairs() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String savedWordPairsString = prefs.getString("wordpairs");
    if (savedWordPairsString != null ) {
      List<WordPairExt> savedWordPairsList = wordPairExtFromJson(
          savedWordPairsString);
      print(savedWordPairsList);
      setState(() {
        _randomWordPairs.addAll(savedWordPairsList);
        _savedWordPairs.addAll(savedWordPairsList);
      });
    }
  }

  Widget _buildList() {
    return ListView.builder(
      padding: const EdgeInsets.all(16.0),
      itemBuilder: (context, item) {
        if (item.isOdd) return Divider();

        final index = item ~/ 2;

        if (index >= _randomWordPairs.length) {
          generateWordPairs().take(10).forEach((wp) {
            _randomWordPairs
                .add(WordPairExt(first: wp.first, second: wp.second));
          });
          //_randomWordPairs.addAll(generateWordPairs().take(10).cast());
        }

        return _buildRow(_randomWordPairs[index]);
      },
    );
  }

  Widget _buildRow(WordPair pair) {
    final alreadySaved = _savedWordPairs.contains(pair);

    return ListTile(
      title: Text(pair.asPascalCase, style: TextStyle(fontSize: 18.0)),
      trailing: Icon(
        alreadySaved ? Icons.favorite : Icons.favorite_border,
        color: alreadySaved ? Colors.red : null,
      ),
      onTap: () {
        setState(() {
          if (alreadySaved) {
            _savedWordPairs.remove(pair);
          } else {
            _savedWordPairs.add(pair);
          }
        });
        _setSavedWordPairs();
      },
    );
  }

  void _pushSaved() {
    Navigator.of(context)
        .push(MaterialPageRoute(builder: (BuildContext context) {
      final Iterable<ListTile> tiles = _savedWordPairs.map((WordPair pair) {
        return ListTile(
            title: Text(pair.asPascalCase, style: TextStyle(fontSize: 16.0)));
      });

      final List<Widget> divided =
          ListTile.divideTiles(context: context, tiles: tiles).toList();

      return Scaffold(
        appBar: AppBar(
          title: Text("Saved WordPairs"),
        ),
        body: ListView(
          children: divided,
        ),
      );
    }));
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("WordPair Generator"),
          actions: <Widget>[
            IconButton(
              icon: Icon(Icons.list),
              onPressed: _pushSaved,
            )
          ],
        ),
        body: _buildList());
  }
}

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: RandomWords(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}