首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >JSON - Flutter只加载一次json列表

JSON - Flutter只加载一次json列表
EN

Stack Overflow用户
提问于 2021-02-12 21:58:36
回答 2查看 58关注 0票数 0

我编写了一段代码,它将从FoodData API- https://fdc.nal.usda.gov/api-guide.html获取数据并将其显示在列表中。我还创建了一个TextField,以便用户可以搜索特定的菜肴。一切都很顺利,但我有个小问题-

该列表每隔几秒刷新一次,以便过滤器列表显示几秒钟,然后该列表转到其初始外观。

我只想让列表加载一次,并且仍然可以让过滤器功能正常工作。

这是我的代码-

代码语言:javascript
运行
复制
import 'dart:async';
import 'dart:convert';

import 'package:fit_app/fitness_app_theme.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<List<FoodGen>> fetchPhotos(http.Client client) async {
  final response =
      await client.get('https://api.nal.usda.gov/fdc/v1/foods/list?dataType=Foundation,SR%20Legacy&pageSize=200&api_key=APIKEY');

  // Use the compute function to run parsePhotos in a separate isolate.
  return compute(parsePhotos, response.body);
}

// A function that converts a response body into a List<Photo>.
List<FoodGen> parsePhotos(String responseBody) {
  final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();

  return parsed.map<FoodGen>((json) => FoodGen.fromJson(json)).toList();
}

class FoodGen {
  int fdcId;
  String description;
  String dataType;
  String publicationDate;
  String ndbNumber;
  List<FoodNutrients> foodNutrients;

  FoodGen(
      {this.fdcId,
      this.description,
      this.dataType,
      this.publicationDate,
      this.ndbNumber,
      this.foodNutrients});

  FoodGen.fromJson(Map<String, dynamic> json) {
    fdcId = json['fdcId'];
    description = json['description'];
    dataType = json['dataType'];
    publicationDate = json['publicationDate'];
    ndbNumber = json['ndbNumber'];
    if (json['foodNutrients'] != null) {
      foodNutrients = new List<FoodNutrients>();
      json['foodNutrients'].forEach((v) {
        foodNutrients.add(new FoodNutrients.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['fdcId'] = this.fdcId;
    data['description'] = this.description;
    data['dataType'] = this.dataType;
    data['publicationDate'] = this.publicationDate;
    data['ndbNumber'] = this.ndbNumber;
    if (this.foodNutrients != null) {
      data['foodNutrients'] =
          this.foodNutrients.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class FoodNutrients {
  String number;
  String name;
  dynamic amount;
  String unitName;
  String derivationCode;
  String derivationDescription;

  FoodNutrients(
      {this.number,
      this.name,
      this.amount,
      this.unitName,
      this.derivationCode,
      this.derivationDescription});

  FoodNutrients.fromJson(Map<String, dynamic> json) {
    number = json['number'];
    name = json['name'];
    amount = json['amount'];
    unitName = json['unitName'];
    derivationCode = json['derivationCode'];
    derivationDescription = json['derivationDescription'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['number'] = this.number;
    data['name'] = this.name;
    data['amount'] = this.amount;
    data['unitName'] = this.unitName;
    data['derivationCode'] = this.derivationCode;
    data['derivationDescription'] = this.derivationDescription;
    return data;
  }
}

class FoodPage extends StatefulWidget {
  FoodPage({Key key}) : super(key: key);

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

class _FoodPageState extends State<FoodPage> {
  TextEditingController editingController = TextEditingController();
  List<FoodGen> dishes;
  List<FoodGen> dishesFilter;
  List<FoodGen> duplicateItems;
  List<FoodGen> dummySearchList = List<FoodGen>();

  @override
  void initState() { 
    super.initState();
  }
  void filterSearchResults(String query) {
    if(dishes == null)return;
    dummySearchList.addAll(dishes);
    if(query.isNotEmpty) {
    List<FoodGen> dummyListData = List<FoodGen>();
      dummySearchList.forEach((item) {
            String queryLowercase = query.toLowerCase(); 
            if(item.description.toLowerCase().startsWith('$queryLowercase')){
              dummyListData.add(item);
        }
        }
      );
      setState(() {
        dishes.clear();
        dishes.addAll(dummyListData);
      });
      return;
    } else {
      setState(() {
        dishes.clear();
        dishes.addAll(duplicateItems);
      });
    }

  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      backgroundColor: FitnessAppTheme.darkBackground,
      body: SafeArea(
        top: true,
        child:Container(
        child: Column(
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8.0),
                child: TextField(
                style: TextStyle(color: Colors.white),

                onChanged: (value) {
                    filterSearchResults(value);
                },
                controller: editingController,
                decoration: InputDecoration(
                    hintStyle: TextStyle(color:FitnessAppTheme.white),
                    labelStyle: TextStyle(color:FitnessAppTheme.white), 
                    labelText: "Search",
                    hintText: "Search",
                    prefixIcon: Icon(Icons.search),
                    border: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(25.0)))),
              ),
              ),

            Expanded(
              child: FutureBuilder<List<FoodGen>>(
                future: fetchPhotos(http.Client()),
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                  dishes = snapshot.data;
                  return snapshot.hasData
                      ? ListView.builder(
 
                        itemCount: dishes.length,
                        itemBuilder: (context, index) {
                          return Card(
                            child: ListTile(title: Text(dishes[index].description))
                          );   
                        },
                      )
                      : Center(child: CircularProgressIndicator());
                  }
                },
              ),
            ),
          ],
        ),
      ),
      ),
    );
  }
}

我非常感谢您在这里的帮助(:

EN

回答 2

Stack Overflow用户

发布于 2021-02-12 22:23:14

只需将fetchPhotos放在类变量中并在FutureBuilder中使用它

代码语言:javascript
运行
复制
var photosRequest;

@override
void initState() {
  photosRequest = fetchPhotos(client);
}

FutureBuilder

代码语言:javascript
运行
复制
builder: photosRequest.then((photos) => filterSearchResults(photos)),

如果从变量调用Future,并且变量不能更改,FutureBuilder就不能再次调用它并使用先前获取的数据。

票数 0
EN

Stack Overflow用户

发布于 2021-02-12 22:49:20

您可以使用提供程序包和Listen: false,这将调用一次,

下面是这个包的示例,希望它能对你有所帮助。

将此代码添加到软件包的pubspec.yaml文件中:

代码语言:javascript
运行
复制
dependencies:
  provider: ^4.3.3



import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

/// This is a reimplementation of the default Flutter application using provider + [ChangeNotifier].

void main() {
  runApp(
    /// Providers are above [MyApp] instead of inside it, so that tests
    /// can use [MyApp] while mocking the providers
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => Counter()),
      ],
      child: const MyApp(),
    ),
  );
}

/// Mix-in [DiagnosticableTreeMixin] to have access to [debugFillProperties] for the devtool
// ignore: prefer_mixin
class Counter with ChangeNotifier, DiagnosticableTreeMixin {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }

  /// Makes `Counter` readable inside the devtools by listing all of its properties
  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(IntProperty('count', count));
  }
}

class MyApp extends StatelessWidget {
  const MyApp({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Example'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: const <Widget>[
            Text('You have pushed the button this many times:'),

            /// Extracted as a separate widget for performance optimization.
            /// As a separate widget, it will rebuild independently from [MyHomePage].
            ///
            /// This is totally optional (and rarely needed).
            /// Similarly, we could also use [Consumer] or [Selector].
            Count(),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        key: const Key('increment_floatingActionButton'),

        /// Calls `context.read` instead of `context.watch` so that it does not rebuild
        /// when [Counter] changes.
        onPressed: () => context.read<Counter>().increment(),
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

class Count extends StatelessWidget {
  const Count({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text(

        /// Calls `context.watch` to make [Count] rebuild when [Counter] changes.
        '${context.watch<Counter>().count}',
        key: const Key('counterState'),
        style: Theme.of(context).textTheme.headline4);
  }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66173166

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档