【问题标题】:Flutter - Saving user dataFlutter - 保存用户数据
【发布时间】:2018-12-21 19:39:49
【问题描述】:

我目前正在创建一个跟踪一般加密数据的应用程序,除了这些数据,我们还发布了为加密爱好者量身定制的新闻文章。此新闻文章数据的各个方面都以字符串形式存储,从图片 url 到发布日期 - 下面的完整列表

我正在寻找一种将这些数据保存到用户设备的方法。在一个完美的情况下,我只是将这些数据保存在 JSON 数组中,但除了不知道如何执行之外,我不确定这是否是保存这些数据以供以后显示的最有效方式。

如果您认为 JSON 是保存这些数据的最佳方式,那么我只需要知道如何将这些数据正确管理到一组不同的已保存文章中,以及如何将其正确导入我的 Dart 代码中。

这个代码的一个例子会很棒,我希望在新年之前发布这个应用程序,所以我需要我能得到的所有帮助。非常感谢。

这是我希望从this source 保存/显示的上述数据:

  • 来源 - source
  • 作者 - author
  • 说明 - description
  • 发布日期 - publishedAt
  • 文章标题 - title
  • 文章的网址 - url
  • 文章图片 - urlToImage

编辑:尝试修改 shadowsheep 的答案以适应索引模型

每个新闻小部件都是一个新的inkwell,它允许构建一个新的scaffold。通过这个scaffold,您可以选择保存文章。保存时,代码目前只是用titledescriptionURLImage URL 更改以下字符串的值。

  • _sTitle
  • _sDescription
  • _sURL
  • _sURLtoImage

我真的很想要一种将数据库(如 shadowsheep 所述)保存到用户设备的方法。这意味着即使用户关闭和打开应用,保存的文章也会在设备上持久保存。

以下代码是我显示新闻数据的确切用例。

CarouselSlider(
 items: [1,2,3,4,5,6,7,8,9,10].map((index) {
    return  Builder(
      builder: (BuildContext context) {
        return Padding(
          padding:  EdgeInsets.only(
            top: 5.0,
            bottom: 20.0,
          ),
          child:  InkWell(
            borderRadius:  BorderRadius.only(
              topLeft: const Radius.circular(15.0),
              topRight: const Radius.circular(15.0),
            ),
            onTap: () {
              print('Opened article scaffold: "' + articles[index].title + "\"");
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) =>  Scaffold(
                    resizeToAvoidBottomPadding: false,
                    appBar:  AppBar(
                      backgroundColor: const Color(0xFF273A48),
                      elevation: 0.0,
                      title: Container(
                        width: _width*0.90,
                        height: 30,
                        padding: const EdgeInsets.only(
                          bottom: 5,
                          top: 5,
                          left: 10,
                          right: 10,
                        ),
                        decoration:  BoxDecoration(
                          color: Colors.white,
                          borderRadius:  BorderRadius.all(
                              Radius.circular(10.0),
                          ),
                        ),
                        alignment: Alignment.center,
                        child:  AutoSizeText(
                          'Published ' +  DateFormat.yMMMd().format(DateTime.parse(articles[index].publishedAt)) + ", "+ DateFormat.jm().format(DateTime.parse(articles[index].publishedAt)),
                          overflow: TextOverflow.ellipsis,
                          maxLines: 1,
                          minFontSize: 5,
                          maxFontSize: 20,
                          textAlign: TextAlign.center,
                          style:  TextStyle(
                            color: Colors.black,
                            fontFamily: 'Poppins',
                          ),
                        ),
                      ),
                    ),
                    body: Center(
                      child:  Scaffold(
                        resizeToAvoidBottomPadding: false,
                        body: Center(
                          child: Container(
                            decoration:  BoxDecoration(
                              gradient:  LinearGradient(
                                begin: Alignment.topCenter,
                                end: Alignment.bottomCenter,
                                colors: [
                                  const Color(0xFF273A48),
                                  Colors.blueGrey
                                ],
                              ),
                            ),
                            padding: const EdgeInsets.only(
                              top: 20,
                              left: 10,
                              right: 10,
                              bottom: 50
                            ),
                            child:  Column(
                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
                              children: <Widget>[
                                  Column(
                                  mainAxisAlignment: MainAxisAlignment.start,
                                  children: <Widget>[
                                      FutureBuilder<Null>(future: _launched, builder: _launchStatus),
                                      AutoSizeText(
                                      articles[index].title,
                                      overflow: TextOverflow.ellipsis,
                                      textAlign: TextAlign.center,
                                      maxFontSize: 30,
                                      minFontSize: 15,
                                      maxLines: 3,
                                      style:  TextStyle(
                                        color: Colors.white,
                                        fontFamily: 'Poppins',
                                      ),
                                    ),
                                      Divider(
                                      color: Colors.transparent,
                                      height: 15.0,
                                    ),
                                    Container(
                                      decoration:  BoxDecoration(
                                        borderRadius:  BorderRadius.circular(15.0),
                                        color: Colors.transparent,
                                        boxShadow: [
                                            BoxShadow(
                                            color: Colors.black.withAlpha(70),
                                            blurRadius: 50.0,
                                          )
                                        ],
                                        image:  DecorationImage(
                                          image:  NetworkImage(articles[index].urlToImage),
                                          fit: BoxFit.fitHeight,
                                        ),
                                      ),
                                      height: 220,
                                      width: 317.5,
                                    ),
                                      Divider(
                                      color: Colors.transparent,
                                      height: 15.0,
                                    ),
                                  ],
                                ),
                                Container(
                                  padding: const EdgeInsets.only(
                                    left: 20,
                                    right: 20
                                  ),
                                  decoration:  BoxDecoration(
                                    color: Colors.transparent,
                                    borderRadius:  BorderRadius.all(
                                        Radius.circular(10.0),
                                    ),
                                  ),
                                  child:  AutoSizeText(
                                    articles[index].description,
                                    overflow: TextOverflow.ellipsis,
                                    textAlign: TextAlign.center,
                                    maxFontSize: 30,
                                    minFontSize: 10,
                                    maxLines: 10,
                                    style:  TextStyle(
                                      color: Colors.white,
                                      fontFamily: 'Poppins',
                                    ),
                                  ),
                                  width: _width*0.90,
                                  height: _height*0.20,
                                ),
                                Container(
                                  padding: const EdgeInsets.all(4.0),
                                  decoration:  BoxDecoration(
                                    color: const Color(0xFF273A48),
                                    borderRadius:  BorderRadius.all(
                                        Radius.circular(10.0),
                                    ),
                                  ),
                                  child: Row(
                                    mainAxisSize: MainAxisSize.min,
                                    mainAxisAlignment: MainAxisAlignment.center,
                                    children: <Widget>[
                                        IconButton(
                                        icon:  Icon(
                                          Icons.favorite_border,
                                          color: Colors.red
                                        ),
                                        iconSize: 35.0,
                                        onPressed: () {
                                          _sTitle = articles[index].title;
                                          _sDescription = articles[index].description;
                                          _sURL = articles[index].url;
                                          _sURLtoImage = articles[index].urlToImage;
                                          Navigator.push(
                                          context,
                                          MaterialPageRoute(builder: (context) => _favoritesScreen())
                                          );
                                        }
                                      ),
                                        IconButton(
                                        icon:  Icon(
                                          Icons.mobile_screen_share,
                                          color: Colors.white,
                                        ),
                                        iconSize: 35.0,
                                        onPressed: () {
                                          Share.share(
                                            articles[index].title + "\n\nCheck out this article at:\n" + articles[index].url + "\n\nLearn more with Cryp - Tick Exchange",
                                          );
                                        }
                                      ),
                                        IconButton(
                                        icon:  Icon(Icons.launch, color: Colors.lightBlueAccent),
                                        iconSize: 32.5,
                                        onPressed: () => setState(() { _launched = _launchInWebViewOrVC(articles[index].url);}),
                                      ),
                                    ],
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                    ),
                  )
                )
              );
            },
            child: Container(
              decoration:  BoxDecoration(
                borderRadius:  BorderRadius.circular(10.0),
                color: const Color(0xFF273A48),
                boxShadow: [
                    BoxShadow(
                    color: Colors.black.withAlpha(70),
                    offset: const Offset(5.0, 5.0),
                    blurRadius: 12.5,
                  )
                ],
                image:  DecorationImage(
                  alignment: Alignment.topCenter,
                  image:  NetworkImage(articles[index].urlToImage),
                  fit: BoxFit.cover,
                ),
              ),
              height: _height*0.35,
              width: _width*0.725,
              child:  Stack(
                children: <Widget>[
                    Align(
                    alignment: Alignment.bottomCenter,
                    child:  Stack(
                      alignment: Alignment.bottomRight,
                      children: <Widget>[
                        Container(
                          padding:  EdgeInsets.only(left: 10.0, right: 10.0),
                          decoration:  BoxDecoration(
                            color: const Color(0xFF273A48),
                            borderRadius:  BorderRadius.only(
                              bottomLeft:  Radius.circular(10.0),
                              bottomRight:  Radius.circular(10.0)
                            ),
                          ),
                          height: 60.0,
                          child:  Column(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: <Widget>[
                                Flexible(
                                child: Container(
                                  width: _width*0.725,
                                  child:  Text(
                                    articles[index].title,
                                    textAlign: TextAlign.center,
                                    overflow: TextOverflow.ellipsis,
                                    maxLines: 2,
                                    style:  TextStyle(
                                      color: Colors.white,
                                      fontFamily: 'Poppins',
                                      ),
                                    ),
                                ),
                              ),
                                Text(
                                'Published ' +  DateFormat.yMMMd().format(DateTime.parse(articles[index].publishedAt)) + ", "+ DateFormat.jm().format(DateTime.parse(articles[index].publishedAt)),
                                overflow: TextOverflow.ellipsis,
                                maxLines: 1,
                                style:  TextStyle(
                                  color: Colors.blueGrey,
                                  fontSize: 10.0,
                                  fontFamily: 'Poppins',
                              ),
                            ),
                          ],
                        )
                      ),
                      Container(
                        width: 25.0,
                        height: 20.0,
                        alignment: Alignment.center,
                        child:  Text(
                          "$index",
                          textAlign: TextAlign.center,
                          style:  TextStyle(
                            color: Colors.blueGrey,
                            fontSize: 10.0,
                            fontFamily: "Poppins"
                          ),
                        )
                      ),
                      ],
                    ),
                  )
                ],
              ),
            ),
          ),
        );
      },
    );
  }).toList(),
  height: 400,
  autoPlay: true,
)

【问题讨论】:

    标签: json file dart flutter filesystems


    【解决方案1】:

    如果你想在 Dart 代码中以持久化的方式保存数据,并且能够在 Android 和 iOS 上使用它,我建议你使用一个 sqlite 插件,像这样:

    https://github.com/tekartik/sqflite

    否则,如果您只需要保存一堆数据,请使用 shared_preferences 插件

    https://github.com/flutter/plugins/tree/master/packages/shared_preferences

    这两个插件都支持Android和iOS

    你请求了很多代码^_^(不是吗)。

    所以首先你需要通过 HTTP 调用来获取你的 json。为此使用http flutter package:

    const request = "https://newsapi.org/v2/top-headlines?sources=crypto-coins-news&apiKey=d40a757cfb2e4dd99fc511a0cbf59098";
    http.Response response = await http.get(request);
    debugPrint("Response: " + response.body);
    

    将其封装在异步方法中:

    void _jsonAndSqlite() async {
    ...
    }
    

    response 变量中,您有您的full JSON

    现在你需要序列化,我建议你这个really good reading

    我为这个答案选择了 Manaul JSON Decoding

    手动JSON解码是指使用内置的JSON解码器 飞镖:转换。它涉及将原始 JSON 字符串传递给 json.decode() 方法,然后在 映射方法返回。它没有外部 依赖项或特定的设置过程,这对于快速 概念证明。

    var myBigJSONObject = json.decode(response.body);
    var status = myBigJSONObject['status'];
    var totalResults = myBigJSONObject['totalResults'];
    var myArticles = myBigJSONObject['articles'];
    
    debugPrint("articles: " + myArticles.toString());
    

    现在我们有文章将尝试通过 Sqflite 包将它们保存在 Sqlite DB 上

    var myFirstArticle = myArticles[0];
    var author = myFirstArticle['author'];
    var title = myFirstArticle['title'];
    
    // Get a location using getDatabasesPath
    var databasesPath = await getDatabasesPath();
    String path = join(databasesPath, 'test.db');
    
    // Delete the database
    await deleteDatabase(path);
    
    // open the database
    Database database = await openDatabase(path, version: 1,
        onCreate: (Database db, int version) async {
      // When creating the db, create the table
      await db.execute(
          'CREATE TABLE Article (id INTEGER PRIMARY KEY, author TEXT, title TEXT)');
    });
    
    // Insert some records in a transaction
    await database.transaction((txn) async {
      int id1 = await txn.rawInsert(
          'INSERT INTO Article(author, title) VALUES("$author", "$title")');
      debugPrint('inserted1: $id1');
    });
    

    就是这样!享受学习和编码的乐趣。阅读我为您发布的关于 JSON 序列化的文章,并尝试使用我的代码,并尝试添加一些其他最佳实践,它们可能更适合您的需求。这只是一个可以玩的快速游乐场。

    所以我最终采用了这种方法:

    [...]
    import 'dart:convert';
    import 'package:http/http.dart' as http;
    import 'package:sqflite/sqflite.dart';
    import 'package:path/path.dart';
    
     [...]
     void _jsonAndSqlite() async {
        const request =
            "https://newsapi.org/v2/top-headlines?sources=crypto-coins-news&apiKey=d40a757cfb2e4dd99fc511a0cbf59098";
        http.Response response = await http.get(request);
        debugPrint("Response: " + response.body);
    
        var myBigJSONObject = json.decode(response.body);
        var status = myBigJSONObject['status'];
        var totalResults = myBigJSONObject['totalResults'];
        var myArticles = myBigJSONObject['articles'];
    
        debugPrint("articles: " + myArticles.toString());
    
        var myFirstArticle = myArticles[0];
        var author = myFirstArticle['author'];
        var title = myFirstArticle['title'];
    
        // Get a location using getDatabasesPath
        var databasesPath = await getDatabasesPath();
        String path = join(databasesPath, 'test.db');
    
        // Delete the database
        await deleteDatabase(path);
    
        // open the database
        Database database = await openDatabase(path, version: 1,
            onCreate: (Database db, int version) async {
          // When creating the db, create the table
          await db.execute(
              'CREATE TABLE Article (id INTEGER PRIMARY KEY, author TEXT, title TEXT)');
        });
    
        // Insert some records in a transaction
        await database.transaction((txn) async {
          int id1 = await txn.rawInsert(
              'INSERT INTO Article(author, title) VALUES("$author", "$title")');
          debugPrint('inserted1: $id1');
        });
      }
    

    【讨论】:

    • 您认为您可以使用提供的值或虚拟字符串给我一个代码示例吗?理想情况下,这将适用于 Dart,但如果您知道这在 JSON 文件中可能是什么样子,那么如果您也可以发布它会很好,这样我就可以更好地了解最终产品的外观。谢谢
    • 谢谢影子,我会尽快看看。
    • 我很快就会得出一个正确的结论,但我认为这可能只是门票。感谢您写得如此出色的回复
    • 感谢您的回答,仔细查看我现在已经能够将其应用于保存titledescription 等,并且我设法在我的 iOS 中找到了database 文件模拟器的隐藏库文件夹。我现在需要管理的只是允许用户删除他们不想再保存的文章,以及如何防止重复条目。我原本打算在所有这些方面寻求帮助,但我已经设法自己完成或正在努力实现它。再次感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-25
    • 1970-01-01
    • 2019-12-19
    • 1970-01-01
    • 2022-12-17
    • 1970-01-01
    相关资源
    最近更新 更多