gpt4 book ai didi

json - Flutter:如果Firebase Storage中的JSON文件已更新,则如何使用Firebase Storage获取新数据

转载 作者:行者123 更新时间:2023-12-03 04:40:48 24 4
gpt4 key购买 nike

我目前正在通过从Firebase Storage调用JSON文件来显示数据,但是我希望这样做,而不是每次都下载JSON文件来显示数据=>我将检查Firebase Store中的JSON文件是否已更改:

  • 如果更改=>将新的JSON文件下载到本地目录并显示它。
  • 否则=>在本地目录中显示旧的JSON文件(此旧JSON文件将在首次打开应用程序时下载)

    关于JSON文件
    将JSON上传到Firebase存储后,这是JSON链接:
    https://firebasestorage.googleapis.com/v0/b/tft-test-48c87.appspot.com/o/loadData.json?alt=media&token=92e3d416-62dc-4137-93a3-59ade95ac38f
    据我所知,此链接由两部分组成:
    第一部分:https://firebasestorage.googleapis.com/v0/b/tft-test-48c87.appspot.com/o/loadData.json 最后一部分:?alt=media&token= + 2e3d416-62dc-4137-93a3-59ade95ac38f(这是中字符串:“downloadTokens”的值,第一部分)
    在该链接的第一部分中,包含有关JSON文件的所有信息,尤其是我认为String “已更新” 的值可以用作是否下载文件的条件。
    例如"updated": "2020-08-04T14:30:10.920Z",每次我上传与旧JSON文件同名的新JSON文件时,此字符串已更新的值都会更改,但链接下载不会更改。

    脚步
    因此,我想执行以下操作:
  • 创建文件以将字符串“updated” 存储在本地目录中(例如,“updated”:null),以及将 JSON文件下载到后的存储位置本地目录
  • 打开应用程序
  • 检查链接第一部分中的字符串“已更新” :
  • 案例A :如果第一部分中的字符串“updated”的值 中的字符串“updated”的!=值本地目录 =>
  • 步骤1:将JSON文件(通过链接:First part + ?alt=media&token= + downloadTokens)下载到本地目录(如果旧的json文件已经存在,它将被替换)
  • 步骤2:在Firebase Storage
  • 中,用本地字符串覆盖 中的字符串“updated”值
  • 步骤3:访问本地目录中的JSON文件以显示数据

  • 情况B :如果中的字符串“updated”的值第一部分 中的字符串“updated”的值本地目录 =>不执行任何操作,仅访问本地目录中的JSON文件以显示数据

  • 我知道对于一个帖子,这是一个很多问题,我是一个有代码的新手,如果我将其分成几篇文章,那么对我来说很难将它们组合在一起。因此,我希望完整代码的答案会很棒。谢谢。这是主文件:
    import 'package:ask/model/load_data_model.dart';
    import 'package:flutter/material.dart';
    import 'package:http/http.dart' as http;

    class LoadDataPage extends StatefulWidget {
    @override
    _LoadDataPageState createState() => _LoadDataPageState();
    }

    class DataServices {
    static const String url = 'https://firebasestorage.googleapis.com/v0/b/tft-test-48c87.appspot.com/o/loadData.json?alt=media&token=92e3d416-62dc-4137-93a3-59ade95ac38f';

    static Future<List<Data>> getData() async {
    try {
    final response = await http.get(url);
    if (200 == response.statusCode) {
    final List<Data> data = dataFromJson(response.body);
    return data;
    } else {
    return List<Data>();
    }
    } catch (e) {
    return List<Data>();
    }
    }
    }

    class _LoadDataPageState extends State<LoadDataPage> {
    @override
    Widget build(BuildContext context) {
    return Scaffold(
    appBar: AppBar(title: Text('Load Data')),
    body: FutureBuilder(
    future: DataServices.getData(),
    builder: (BuildContext context, AsyncSnapshot snapshot) {
    List<Widget> children;
    List<Data> _data = snapshot.data;
    if (snapshot.hasData) {
    return ListView.builder(
    itemCount: _data.length,
    itemBuilder: (context, index) {
    return Column(
    children: [Text(_data[index].data)],
    );
    },
    );
    } else {
    children = <Widget>[SizedBox(child: CircularProgressIndicator(), width: 60, height: 60), const Padding(padding: EdgeInsets.only(top: 16), child: Text('Loading...'))];
    }
    return Center(child: Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: children));
    }));
    }
    }


    另一个步骤
    EdwynZN的答案对我来说非常有效,但是,我编辑该帖子以添加更多案例,我认为这将使加载页面尽快,所以请再次帮助我:
    打开页面后=> ==> readFile> compareLastUpdate_lastUpdateDB
  • 案例A :首次打开应用程序=> _createFile:否> readFile_lastUpdateDB>再次是_createFile
  • 案例B :不是第一次打开应用程序:
  • 数据仍然立即从旧的JSON加载,同时在后台运行:readFile:
  • 如果更新时间相同=>不执行
  • 如果更新时间不同=> compareLastUpdate_lastUpdateDB



  • P / S:通过此流程,他们第二次打开页面,然后将显示新数据,对吗?但是我想知道如果在新的JSON文件被覆盖到旧的JSON文件=>之后使用_createFile =>,那么电话屏幕会在那之后显示新数据吗?

    最佳答案

    我建议使用shared_preferences将最后更新的日期另存为字符串

    import 'package:shared_preferences/shared_preferences.dart';
    import 'package:path_provider/path_provider.dart';
    import 'dart:convert';


    /// Move them outside of the class as Top Level functions
    List<Data> readFile(File file) {
    try{
    String data = file.readAsStringSync();
    return dataFromJson(data);
    } catch(e){
    print(e.toString());
    return List<Data>(); // or return an empty list, up to you
    }
    }

    // No need of encoder now because response body is already a String
    void writeFile(Map<String, dynamic> arg) =>
    arg['file']?.writeAsStringSync(arg['data'], flush: true);

    class DataServices {

    DateTime dateApi;

    static const String url = 'https://firebasestorage.googleapis.com/v0/b/tft-test-48c87.appspot.com/o/loadData.json?alt=media&token=92e3d416-62dc-4137-93a3-59ade95ac38f';
    static const String urlUpdate = 'https://firebasestorage.googleapis.com/v0/b/tft-test-48c87.appspot.com/o/loadData.json';

    Future<List<Data>> getData() async {
    bool update = await compareLastUpdate;
    if(update) { // that means the update times are the same, so retrieving form json file is better than doing http request
    final file = await _createFile();
    if(await file.exists()) return await compute(readFile, file);
    else return null; //or an empty List
    // If it doesn't exists (probably first time running the app)
    // then retrieve an empty list, null or check how to fill the list from somewhere else
    }
    try {
    final response = await http.get(url);
    final SharedPreferences preferences = await SharedPreferences.getInstance();
    if (200 == response.statusCode) {
    final String utfData = utf8.decode(response.bodyBytes); //just decode it yourself instead of using response.body which uses [latin1] by default
    final List<Data> data = await compute(dataFromJson, utfData);
    final file = await _createFile();
    Map<String, dynamic> args = {
    'file': file,
    'data': utfData
    //'data': response.body // pass the return body instead of the data
    };
    await compute(writeFile, args);
    await preferences.setString('updateDate', dateApi.toString()); //Save the new date
    return data;
    } else {
    return List<Data>();
    }
    } catch (e) {
    return List<Data>();
    }
    }

    File _createFile() async{
    Directory tempDir = await getTemporaryDirectory(); // or check for a cache dir also
    return File('${tempDir.path}/Data.json');
    }


    Future<bool> get compareLastUpdate async{
    final dateCache = await _lastUpdateDB;
    dateApi = await _lastUpdateApi;

    if(dateCache == null) return false;
    return dateApi?.isAtSameMomentAs(dateCache) ?? false; // or just isAfter()
    // If dateApi is null (an error conection or some throw) just return false or throw an error and
    // catch it somewhere else (and give info to the user why it couldn't update)
    }

    Future<DateTime> get _lastUpdateApi async{
    try {
    final response = await http.get(urlUpdate);
    DateTime dateTime;
    if (200 == response.statusCode) {
    final data = jsonDecode(response.body));
    dateTime = DateTime.tryParse(data['updated'] ?? '');
    }
    return dateTime;
    } catch (e) {
    return null;
    }
    }

    Future<DateTime> get _lastUpdateDB async{
    final SharedPreferences preferences = await SharedPreferences.getInstance();
    return DateTime.tryParse(preferences.getString('updateDate') ?? ''); // Or if it's null use an old date
    // The first time the app opens there is no updateDate value, so it returns null, if that
    // happens replace it by an old date, one you know your api will be always newer,
    // Ex: 1999-08-06 02:07:53.973 Your Api/App didn't even exist back then
    // Or just use an empty String so the tryParser returns null
    }
    }
    然后,在小部件中只需将其命名为
    class _LoadDataPageState extends State<LoadDataPage> {
    final DataServices services = DataServices();

    @override
    Widget build(BuildContext context) {
    return Scaffold(
    appBar: AppBar(title: Text('Load Data')),
    body: FutureBuilder(
    future: services.getData(),
    builder: (BuildContext context, AsyncSnapshot snapshot) {
    List<Widget> children;
    List<Data> _data = snapshot.data;
    if (snapshot.hasData) {
    return ListView.builder(
    itemCount: _data.length,
    itemBuilder: (context, index) {
    return Column(
    children: [Text(_data[index].data)],
    );
    },
    );
    } else {
    children = <Widget>[SizedBox(child: CircularProgressIndicator(), width: 60, height: 60), const Padding(padding: EdgeInsets.only(top: 16), child: Text('Loading...'))];
    }
    return Center(child: Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: children));
    }));
    }
    }
    yu也可以检查 Dio package,它在http上具有一些功能,可让您向url添加参数

    关于json - Flutter:如果Firebase Storage中的JSON文件已更新,则如何使用Firebase Storage获取新数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63251355/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com